はてブロ@ama_ch

https://twitter.com/ama_ch

Python Challenge Level6

※ネタバレ有り

考え方

タイトルは「now there are pairs」。ペアがあるらしい。
画像はズボンのチャックですね。ペアといい、zip()関数を使うのかな?


パッと見てわかるのはこのくらいなので、ソースを開いてみます。
なんかでっかいコメントがある!

<!-- The following has nothing to do with the riddle itself. I just
thought it would be the right point to offer you to donate to the
Python Challenge project. Any amount will be greatly appreciated.

-thesamet
-->

和訳

以下は問題自身と関係ありません。私はただ
Python Challengeプロジェクトへの寄付をお願いしたいと思います。
いくらでもありがたいです。

問題と関係なかった・・・寄付も考えておきますね!


これが関係ないとなると、実際の問題のソースは

<html> <!-- <-- zip -->
<head>
  <title>now there are pairs</title>
  <link rel="stylesheet" type="text/css" href="../style.css">
</head>
<body>
<center>
<img src="channel.jpg">
<br/>

これでほぼ全部ですね。
ヒントっぽいところは、最初の行の

<!-- <-- zip -->

ここくらい。段々ハードルが上がってきたぞ!


ここで一旦挫折><
このzipというのが全然わからなくて、Google先生に聞いてみました。


・・・


どうやら、拡張子をzipにするらしい!
http://www.pythonchallenge.com/pc/def/channel.zip
ダウンロードしてzipの中身を覗いてみると、

$ ls
100.txt     19478.txt   30257.txt   41004.txt   52400.txt   63949.txt   73840.txt   82852.txt   91285.txt
10134.txt   19812.txt   30318.txt   41055.txt   5289.txt    63997.txt   74219.txt   8289.txt    91316.txt
1035.txt    19822.txt   30339.txt   4130.txt    53027.txt   64045.txt   7422.txt    82896.txt   91523.txt
--- 中略 ---
1866.txt    29446.txt   40033.txt   51696.txt   63031.txt   72782.txt   82371.txt   9058.txt    99905.txt
18751.txt   29494.txt   40068.txt   51783.txt   63032.txt   72946.txt   82430.txt   90763.txt   readme.txt
1878.txt    29521.txt   40210.txt   51833.txt   63154.txt   7298.txt    82431.txt   90792.txt
18922.txt   29704.txt   40257.txt   52069.txt   63181.txt   730.txt     82483.txt   90923.txt
18987.txt   29789.txt   40377.txt   52149.txt   63191.txt   73256.txt   82519.txt   90949.txt
19069.txt   29834.txt   404.txt     52184.txt   63414.txt   73281.txt   8258.txt    90980.txt
19185.txt   29858.txt   40413.txt   52205.txt   63528.txt   7331.txt    82593.txt   91038.txt
19311.txt   29888.txt   40521.txt   52323.txt   63643.txt   73389.txt   82706.txt   91046.txt
19413.txt   29994.txt   40627.txt   52349.txt   63804.txt   73422.txt   82785.txt   91136.txt
1946.txt    30076.txt   40940.txt   52390.txt   63875.txt   73718.txt   82814.txt   9118.txt

うおー沢山ファイルある!
readme.txtがあるので、見てみましょう。

$ cat readme.txt 
welcome to my zipped list.

hint1: start from 90052
hint2: answer is inside the zip

ふむふむ。90052.txtを見てみよう。

$ cat 90052.txt 
Next nothing is 94191

どっかで見覚えのある感じですね!
レベル4で同じようなことをやってたので、このソースを流用して書いてみました。

#!/usr/bin/env python
#! -*- coding: utf-8 -*-
""" level 6
http://www.pythonchallenge.com/pc/def/channel.html
"""
import re

def textchain(fname):
    f = open(fname)
    src = f.read()
    f.close()
    next = re.findall("[0-9]+", src)
    print src
    if next:
        textchain(next[0] + ".txt")

if __name__ == "__main__":
    textchain("90052.txt")

実行結果

$ python level6.py
Next nothing is 94191
Next nothing is 85503
Next nothing is 70877
--- 中略 ---
Next nothing is 68628
Next nothing is 67824
Next nothing is 46145
Collect the comments.

あ、アルェー? 答えじゃない!
コメントっていったいなんだ・・・ 他にファイルなんてないしなぁ。


いくら考えてもわからないので、ここで再びGoogle先生に尋ねてみました。


・・・


むむ、zipfileというモジュールを使うらしい。
ちょっと寄り道してzipfileモジュールの使い方を勉強する。
http://www.m-takagi.org/docs/python/lib/module-zipfile.html

>>> import zipfile
>>> file = zipfile.ZipFile("channel.zip")
>>> file.getinfo("90052.txt")
<zipfile.ZipInfo object at 0x9c1f90>
>>> file.getinfo("90052.txt").comment
'*'

getinfo("アーカイブ内のファイル名").commentで、アーカイブメンバへのコメントを確認できることがわかりました!


そういえばreadme.txtの

hint2: answer is inside the zip

これはzip内のコメントを参照しろということかぁ。


気を取り直して、コメントも読み込むように先ほどのソースを改造しました!

回答

#!/usr/bin/env python
#! -*- coding: utf-8 -*-
""" level 6
http://www.pythonchallenge.com/pc/def/channel.html
"""
import re
import zipfile

file = zipfile.ZipFile("channel.zip")
o = []

def textchain(fname):
    f = open(fname)
    src = f.read()
    f.close()
    next = re.findall("[0-9]{2,}", src)
    print src
    if next:
        o.append(file.getinfo(next[0] + ".txt").comment)
        textchain(next[0] + ".txt")

if __name__ == "__main__":
    textchain("readme.txt")
    print "".join(o)

channel.zipを解凍したディレクトリに、再度channel.zipを用意して実行します。
実行結果

$ python level6.py
Next nothing is 94191
Next nothing is 85503
Next nothing is 70877
--- 中略 ---
Next nothing is 68628
Next nothing is 67824
Next nothing is 46145
Collect the comments.
****************************************************************
****************************************************************
**                                                            **
**   OO    OO    XX      YYYY    GG    GG  EEEEEE NN      NN  **
**   OO    OO  XXXXXX   YYYYYY   GG   GG   EEEEEE  NN    NN   **
**   OO    OO XXX  XXX YYY   YY  GG GG     EE       NN  NN    **
**   OOOOOOOO XX    XX YY        GGG       EEEEE     NNNN     **
**   OOOOOOOO XX    XX YY        GGG       EEEEE      NN      **
**   OO    OO XXX  XXX YYY   YY  GG GG     EE         NN      **
**   OO    OO  XXXXXX   YYYYYY   GG   GG   EEEEEE     NN      **
**   OO    OO    XX      YYYY    GG    GG  EEEEEE     NN      **
**                                                            **
****************************************************************
 **************************************************************

おおお、できた!
早速確認してみます。

it's in the air. look at the letters.

http://www.pythonchallenge.com/pc/def/hockey.html

んん?
「それは空気の中です。文字を見なさい。」?
とりあえず文字を見てみる。


・・・あ!そうか!
HOCKEYのそれぞれの文字を構成するアルファベットが、それぞれOXYGENになっていますね。
なるほどoxygen(酸素)なら空気中にあるよね。
こいつをURLに打ち込んだところ、無事次の問題にたどり着きました。

感想

もう自力で解くの無理><
ぐぐりまくって、必要なモジュールの使い方を勉強するって感じです。