Python/Python Challenge

[Python Challenge 18] 즐거운 다른그림찾기놀이

Python Challenge 18의 Url은 다음과 같다

Python challenge 18 : http://www.pythonchallenge.com/pc/return/balloons.html


구성

Title은 "Can you tell the difference"이다. 번역하면 "차이점을 말할 수 있는가?" 이다.  문제 자체가 조금 번잡한 편에 속하기 때문에, 바로 해결 아이디어로 들어가 보겠다.


해결 아이디어

우선 진짜문제가 담겨 있는 곳은 이곳이 아니다. 차이점은 '밝기', 영어로 하면 'brightness'이다. 일단 진짜 문제의 url인 brightness.html로 이동하자

http://www.pythonchallenge.com/pc/return/brightness.html

구성은 동일하다.

단 주석창에 새로운 힌트가 생겼다.

deltas.gz로 url을 접근하면 gunzip파일을 다운로드 받을 수 있다. 안에는 txt파일인 data가 들어있다 내부는 다음과 같다.

하나의 파일은 아닌것으로 보인다. 제일 위에 줄인 89 50 4e 47은 PNG 파일의 시그니처이다. 중간 \t같은 공백을 기준으로 왼쪽 파일, 오른쪽 파일에 동일한 89 50 4e 47이 있는 것으로 보아 두 파일은 별개의 파일이다. 쪼개서 png를 만든 결과는 다음과 같다..... 이 X발 티스토리 업로드 가 이상하다. 하여간 두 파일을 PNG로 잘 쪼개었다면 축하한다....

 

"필자와 동일하게 문제 잘못 풀고 있는거다"

 

일단 문제를 푸는 희망은 delta라는 gunzip파일의 이름이다. delta라는건 편차라고 흔히 이야기한다. bightness에서 나왔던 difference라는 단어를 같이 구글링 하면 difflib라는 모듈을 찾을 수 있다.

https://docs.python.org/ko/3/library/difflib.html

 

difflib — 델타 계산을 위한 도우미 — Python 3.9.5 문서

difflib — 델타 계산을 위한 도우미 소스 코드: Lib/difflib.py 이 모듈은 시퀀스 비교를 위한 클래스와 함수를 제공합니다. 예를 들어 파일을 비교하는 데 사용할 수 있으며, HTML 및 문맥(context)과 통

docs.python.org

difflib은 두 문자열의 차이점을 표현해주는 모듈로 대충 아래와 같은 동작을 한다.

그러니까 위 delta.gz에 있는 공백 기준 왼쪽과 오른쪽의 차이를 보고 출력을 하는 코드를 만들면 다음과 같은데,

### 18_1.py

import gzip, difflib

if __name__=="__main__" :
    dat = gzip.open("deltas.gz","rb")

    left = list()
    right = list()
    for line in dat :
        left.append(line[:53].decode())
        right.append(line[56:-1].decode())
        

    diff = difflib.Differ().compare(left,right)

    for x in diff :
        print(x)

이것의 출력 결과는 다음과 같다.

  89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00
  
  ...
  
+ 01 50 00 00 00 8f 08 06 00 00 00 ac f7 83 97 00 00 00
  7e 8e f8 2a a1 a1 4b 0c 86 34 2e 31 90 29 8c 16 cd 12
- b7 50 46 d5 db 73 cc d0 7d 03 d3 37 80 52 88 d7 03 76
+ 09 70 48 59 73 00 00 0b 13 00 00 0b 13 01 00 9a 9c 18
  f3 6b be 5a e2 f6 7c 9a 63 78 fe a0 03 5a 55 7b fa 30
- 9f bf 06 92 54 a1 02 81 10 e8 8f 25 20 a3 a1 1a 0b dd
+ 00 00 00 07 74 49 4d 45 07 d5 05 07 0a 37 11 2c 30 95
  a3 3c 20 74 68 c1 a4 48 11 c8 b3 5b f3 aa e5 66 c9 f3
- 39 e8 c6 42 b5 16 ca 1a 3a e6 2a 75 f3 b8 ab f6 c4 84
+ e5 00 00 00 1d 74 45 58 74 43 6f 6d 6d 65 6e 74 00 43
  17 fe e9 ab 81 36 57 f9 54 ed 57 34 4a 29 4d 29 eb e7
+ 72 65 61 74 65 64 20 77 69 74 68 20 54 68 65 20 47 49
  65 1b ae 35 cc 54 ed 2f 79 be 08 f3 78 85 ef 2c 08 54
  a9 e1 50 4d 2c 25 29 e5 96 2c 41 31 42 cb 8d 43 07 a0
+ 4d 50 ef 64 25 6e 00 00 20 00 49 44 41 54 78 da ed 7d
  e3 ae e6 d5 07 87 67 03 3b c6 b4 a4 4a c3 58 24 06 96
  
  ...

그러니까 이 +과 -를 판단해서 왼쪽 파일, 오른쪽 파일, 공통 파일을 만들어서 넣으면 되는 거다.( 참 조금 독특한 점은 기존 delta는 -와 +이 아닌 공백(" ")은 공통적인 문자열을 지칭해서 이번 문제에서도 공통+"+". png와 공통+"-". png 2개를 만들면 된다고 생각을 했는데, "+"과 "-"와 " "으로 3가지를 만들어야 해결이 된다. 헤더도 3개가 따로 있다.)

 

이를 구현한 코드는 다음과 같다. 

### 18_2.py

import gzip, difflib

if __name__=="__main__" :
    dat = gzip.open("deltas.gz","rb")

    left = list()
    right = list()
    for line in dat :
        left.append(line[:53].decode())
        right.append(line[56:-1].decode())
        

    diff = difflib.Differ().compare(left,right)
    
    comm = open("comm.png", "wb")
    left = open("left.png", "wb")
    right = open("right.png", "wb")

    for line in diff :
        bs = bytes([int(x, base=16) for x in line[2:].strip().split(" ") if x])
        if(line[0] == '+'):
            left.write(bs)
        elif(line[0] == '-'):
            right.write(bs)
        else:
            comm.write(bs)

    comm.close()
    left.close()
    right.close()

출력은 다음과 같다.

left.png
right.png
comm.png

공통 사진인 comm.png경로부터 찾아보자 들어가려고 하면 자격증명을 물어본다. 국룰인 huge/file을 해보면 틀리다. butter/fly로 접근을 하면 축하한다. 찾은 거다

Answer Url : http://www.pythonchallenge.com/pc/hex/bin.html


비 고사항인데, 필자는 이거 푸는 게 너무 어려웠다.

difflib모듈은 사용해봤어도 생각도 못하고 있었다. 치열한 전투의 흔적을 남기며 다음 글에서 뵙겠습니다.

<전투의흔적.png>