The Python Challenge

目录

Level 0

output = 2 ** 38  
print output  

Level 1

import string

source = "g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amknsrcpq ypc dmp. bmgle gr gl zw fylb gq glcddgagclr ylb rfyr'q ufw rfgq rcvr gq qm jmle. sqgle qrpgle.kyicrpylq() gq pcamkkclbcb. lmu ynnjw ml rfc spj."

t_from = [chr(i) for i in xrange(ord('a'), ord('a') + 26)]  
t_to = [chr(ord(i) + 2) for i in t_from]  
t_to[24] = 'a'  
t_to[25] = 'b'

table = string.maketrans(''.join(t_from), ''.join(t_to))

print source.translate(table)  
print "map".translate(table)  

Level 2

这题我猜中了开头,却没猜中结尾。 首先是根据提示

  1. Look at the page source
  2. Look for exceptional characters.
# 下载数据
import urllib2  
import re

url = "http://www.pythonchallenge.com/pc/def/ocr.html"  
fp = urllib2.urlopen(url)  
pattern = re.compile(ur"\<!--.*--\>", re.S)  
html = fp.read()  
mess_data = re.findall(pattern, html)  
mess_data = mess_data[0].split("\n\n")[1].split('\n')

source = "\n".join(mess_data[1:-1])  
char = dict()  
for i in xrange(33, 127):  
    count = source.count(chr(i))
    if count == 0:
        continue
    char[chr(i)] = count
print char # 这里可以看到字母只出现了一次  

其实做到这里就应该出答案了,但是因为这个是按照字母表出现的顺序,所以出来的结果是aeilqtuy,然后果断404了。 最后参考了下这里

print "".join(re.findall("[A-Za-z]", source))  

Level 3

我的答案是这样的

import re  
import urllib2

url = "http://www.pythonchallenge.com/pc/def/equality.html"  
fp = urllib2.urlopen(url)  
pattern = re.compile(ur"\<!--(.*)--\>", re.S)  
html = fp.read()  
mess_data = re.findall(pattern, html)[0]


print "".join(re.findall(ur"[A-Z]{3}([a-z])[A-Z]{3}", mess_data))  

我能说我不看清题意吗?三个大个子围住一个小个子,也就是『大大大小大大大』,尼玛,没注意到可能是『大大大大小大大大小』或者『小大大大小大大大大』或者『大大大大小大大大大』 所以正则表达式应该是这样的[^A-Z][A-Z]{3}([a-z])[A-Z]{3}[^A-Z]

Level 4

直接给出解决办法

import urllib2  
import re

url = "http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing={num}"

def go_to_next(next_num):  
    fp = urllib2.urlopen(url.format(num=next_num))
    source = fp.read()
    print "try {num}\nthe source is '{source}'".format(num=next_num, source=source)
    key = re.compile(ur"\d+")
    next_num = re.findall(key, source)[-1]
    go_to_next(next_num)

try:  
    go_to_next(12345)
except Exception, e:  
    print e

从12345开始会收到一次异常,得到的数字除以2,然后再继续下去就得到了下一题了。

Level 5

什么都别说了

import urllib2  
try:  
    import cPickle as pickle
except ImportError:  
    import pickle

url = "http://www.pythonchallenge.com/pc/def/banner.p"

fp = urllib2.urlopen(url)

source = fp.read()

source = pickle.loads(source)  
content = ''

for i in source:  
    for j in i:
        print j[0] * j[1],
        content += j[0] * j[1]
    content += "\n"

print content

Level 5

都是有联系的,字母也不是乱排序的

import urllib2  
import zipfile  
import re

url = "http://www.pythonchallenge.com/pc/def/channel.zip"

fp = urllib2.urlopen(url)

open("6.zip", "w").write(fp.read())


content = ''  
with zipfile.ZipFile("6.zip", "r") as myzip:  
    namelist = myzip.namelist()
    key = re.compile(ur'\d+')

    def go_to(next_num):
        global content
        filename = "{next_num}.txt".format(next_num=next_num)
        ouput = myzip.read(filename)
        print ouput
        content += myzip.getinfo(filename).comment
        next_num = re.findall(key, ouput)[0]
        go_to(next_num)

    try:
        go_to(90052)
    except Exception, e:
        print e

    print content

首先从 zip 文件里发现 readme.txt,然后从里面知道了90052。

Level 6

import urllib2  
import zipfile  
import re

url = "http://www.pythonchallenge.com/pc/def/channel.zip"

fp = urllib2.urlopen(url)

open("6.zip", "w").write(fp.read())


content = ''  
with zipfile.ZipFile("6.zip", "r") as myzip:  
    namelist = myzip.namelist()
    key = re.compile(ur'\d+')

    def go_to(next_num):
        global content
        filename = "{next_num}.txt".format(next_num=next_num)
        ouput = myzip.read(filename)
        print ouput
        content += myzip.getinfo(filename).comment
        next_num = re.findall(key, ouput)[0]
        go_to(next_num)

    try:
        go_to(90052) # 从 README.txt 获取
    except Exception, e:
        print e

    print content

Level 7

这一题做不出来,涉及到了图像的处理

像素(pixel),一个点,由 RGB 组成。

import re, Image

i = Image.open("oxygen.png") # http://www.pythonchallenge.com/pc/def/oxygen.png  
row = [i.getpixel((x, 45)) for x in range(0, i.size[0], 7)]  
ords = [r for r, g, b, a in row if r == g == b]

print "".join(map(chr, map(int, re.findall("\d+", "".join(map(chr, ords))))))  

这不是我做出来的 PIL的替代Pillow文档

Level 8

从 HTML 里看到了链接,还有 un 和 pw,点击链接后,出现了 HTTP basic auth,所以,un 肯定是 username,pw 肯定是 password 了,然后尝试直接print,但是输出乱码,然后发现 un 和 pw 都是BZh91AY&SY,然后搜了一下,发现是bz2压缩的头,所以就很简单了

import bz2

print bz2.decompress(un)  
print bz2.decompress(pw)  

@ 2016-04-26 20:28

Level 9

看了半天,想歪了,然后搜了一圈,发现了几种不同的思路,然后去看 Pillow 的文档,在 ImageDraw这里,有一个 PIL.ImageDraw.Draw.line的函数,支持三个参数,第一个参数,可以是[(x0, y0), (x1, y1)]或者[x0, y0, x1, y1],然后再去看 first 和 second,就发现,貌似就是[x0, y0, x1, y1]这种格式的数据了

from PIL import Image, ImageDraw

# first = ...
# second = ...
first = map(lambda x: int(x.strip()), first.split(','))  
second = map(lambda x: int(x.strip()), second.split(','))

im = Image.open("good.jpg")

draw = ImageDraw.Draw(im)  
draw.line(first, fill="red", width=1)  
draw.line(second, fill="red", width=1)

im.show()  

出来了一个牛,然后替换成 cow 后,又是 HTTP basic auth,然后发现并没有用户名和密码相关的提示,就用 Level 8 中的 un 和 pw 试了一下,然后就正确的通过了,提示说是公的,然后就想到 cow 是奶牛,然后就又去看了下图,发现确实没说是母牛:D,那就是 bull 了

@ 2016-04-27 22:54

Level 10

刚看到时,当做数学题来做了,毕竟也是读过高中了,学过数列了,不停的计算,然后发现智商太低算不出来,然后搜了一下,发现原来也是数列,只不过是 Look-and-say sequence,看了 WiKi 知道规律后,就开始写了,刚开始用递归,然后在第26次的时候RuntimeError: maximum recursion depth exceeded,然后顺带搜了下,在 CPython 实现里,最大递归数是有限制的,可以由sys.getrecursionlimit()得到,在我的电脑里,Python 2.7.10,OS X 10.11.4,最大递归数是1000,但是可以通过sys.setrecursionlimit来设置,不过最大的可设置数还是有限制:"The highest possible limit is platform-dependent"。

##### 以下代码可能出现 RuntimeError 异常
def run(num):  
    res = list()

    def next_num(num):
        if not num:
            return res

        first = num[0]
        next_index = 0
        if num[next_index:].startswith(first * 3):
            res.append('3' + first)
            next_index = next_index + 3
        elif num[next_index:].startswith(first * 2):
            res.append('2' + first)
            next_index = next_index + 2
        else:
            res.append('1' + first)
            next_index = next_index + 1
        return next_num(num[next_index:])

    next_num(num)
    return ''.join(res)

start = '1'  
for i in xrange(30):  
    start = run(start)
    print i, start

然后就网上搜了下『递归转循环』,顺带看了下知乎这个问题关于这个的讨论。下面是循环实现

def next_num(num):  
    res = list()

    next_index = 0
    for i in xrange(0, len(num)):
        if next_index >= len(num):
            break
        first = num[next_index]
        if num[next_index:].startswith(first * 3):
            res.append('3' + first)
            next_index = next_index + 3
        elif num[next_index:].startswith(first * 2):
            res.append('2' + first)
            next_index = next_index + 2
        else:
            res.append('1' + first)
            next_index = next_index + 1

    return ''.join(res)

start = '1'  
a = [start]  
for i in xrange(30):  
    start = next_num(start)
    print i, start
    a.append(start)
print len(a[30])  

@ 2016-04-28 22:08

Level 11

首先到看图就感觉是两张图合在一起了,然后看到了标题的 odd 和 even,然后就去想办法把这个给拆出来,但是去看 pillow 的文档,只有把俩图合一张图的接口,并没有拆出来的,所以就觉得得自己手动拆开,然后死活拆不出来,寻求帮助后,得到了下列的结果

from PIL import Image

im = Image.open('cave.jpg')  
odd_im = Image.new(im.mode, (im.size[0] / 2, im.size[1] / 2))


def is_odd(number):  
    return bool(number % 2)


def is_even(number):  
    return not is_odd(number)

for x in xrange(im.size[0]):  
    for y in xrange(im.size[1]):
        if is_even(x) and is_even(y):
            odd_im.putpixel((x / 2, y / 2), im.getpixel((x, y)))
        elif is_odd(x) and is_even(y):
            odd_im.putpixel(((x - 1) / 2, y / 2), im.getpixel((x, y)))
        elif is_odd(x) and is_odd(y):
            odd_im.putpixel(((x - 1) / 2, (y - 1) / 2), im.getpixel((x, y)))
        else:
            odd_im.putpixel((x / 2, (y - 1) / 2), im.getpixel((x, y)))


odd_im.show()

上面就是把一张图,减小到 1/4 张图上去。

@ 2016-05-04 21:15