Python 3 Module Examples
Python 3 Module Examples
of Contents
Introduction
1.1
Level 0
1.2
Level 1
1.3
Level 2
1.4
Level 3
1.5
Level 4
1.6
Level 5
1.7
Level 6
1.8
Level 7
1.9
Level 8
1.10
Level 9
1.11
Level 10
1.12
Level 11
1.13
Level 12
1.14
Level 13
1.15
Level 14
1.16
Level 15
1.17
Level 16
1.18
Level 17
1.19
Level 18
1.20
Level 19
1.21
Level 20
1.22
Level 21
1.23
Level 22
1.24
Level 23
1.25
Level 24
1.26
Level 25
1.27
Level 26
1.28
Level 27
1.29
Level 28
1.30
Level 29
1.31
Level 30
1.32
Level 31
1.33
Level 32
1.34
Level 33
1.35
Appendix: Links
1.36
Introduction
Learning Python
This eBook provides "just enough" knowledge for solving each challenge. To learn
more about Python, try these resources:
The Official Documentation: not always friendly for beginners, but it should be
treated as the single source of truth.
Books: books can be slightly outdated, however they may provide better entry
level tutorials, or dig deeper in a specific topic
Basics: Learning Python
More Advanced: Effective Python
Machine Learning: Python Machine Learning
Data Analysis: Python for Data Analysis
Data Visualization: Data Visualization with Python and JavaScript
Hacking: Black Hat Python
Web Scraping: Web Scraping with Python
HackingNote: last but not least, a shameless plug-in. I'm still learning Python,
and I'm taking notes and shaping my knowledge base along the way. Hope it
could help you as well.
Introduction
Level 0
Problem
Explore
As the "0" indicates, this is just a warm up.
Loop
The naive way to solve it: multiply by 2 in a loop:
Level 0
>>> k = 1
>>> for i in range(38):
... k *= 2
...
>>> k
274877906944
Power
Use ** for power:
>>> 2**38
274877906944
In REPL the result will be printed; or you can explicitly print the result by calling
print()
>>> print(2**38)
274877906944
or
>>> print(pow(2,38))
274877906944
Shift
Multiply by 2 is equivalent to shifting the binary representation left by one:
Level 0
>>> 1<<38
274877906944
Numeric Types
Done!
Wait, why 38? what is implied?
If you are coming from C/C++, Java or other languages, you know that there are
multiple types just for integers: short , integer , long , and even
BigInteger beyond 64-bit. However that is not the case in Python:
>>> type(2**3)
<class 'int'>
>>> type(2**38)
<class 'int'>
>>> type(2**380)
<class 'int'>
Complete Solution
print(2**38)
Output:
Level 0
274877906944
Next Level
http://www.pythonchallenge.com/pc/def/274877906944.html
And it will jump to
http://www.pythonchallenge.com/pc/def/map.html
Read More
Python 3 - REPL
Level 1
Problem
Level 1
Hints
The text must be encoded.
Hint from url: map. And notice that there's exactly one character between the
given pairs: K->L->M , O->P->Q , E->F->G , and look at the very first letter in
the text g , if this is English, a good guess is that g is actually i . What is the
distance from g to i ? Yes, G->H->I . So let's shift each character to the
right, by 2, and y back to a , z back to b .
The string is not so long, so let's just copy and past it to REPL:
>>> raw = "g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amk
nsrcpq ypc dmp. bmgle grgl zw fylb gq glcddgagclr ylb rfyr'q ufw
rfgq rcvr gq qm jmle. sqgle qrpgle.kyicrpylq() gq pcamkkclbcb.
lmu ynnjw ml rfc spj."
Solution 1
The pair of functions that would help up make the change:
ord() : character to integer
chr() : integer to character
e.g.
>>> chr(65)
'A'
>>> ord('A')
65
To shift a character:
10
Level 1
>>> ord('k')
107
>>> ord('k') + 2
109
>>> chr(ord('k') + 2)
'm'
11
Level 1
That is how we make a loop in Java or C, but python has a better way: list
comprehension
>>> ''.join([chr(((ord(s) + 2) - ord('a')) % 26 + ord('a')) if s
>= 'a' and s <= 'z' else s for s in raw])
"i hope you didnt translate it by hand. thats what computers are
for. doing itin by hand is inefficient and that's why this text
is so long. using string.maketrans() is recommended. now apply
on the url."
12
Level 1
Solution 2: .maketrans()
In Python 3, .maketrans is not in string as indicated; instead call
str.maketrans() or bytes.maketrans()
Solution 3
Let's have our own version of maketrans. The inputs are two lists, then each
character is mapped from one list to another.
Define the two lists
13
Level 1
zip them
>>> list(zip(a, b))
[('a', 'c'), ('b', 'd'), ('c', 'e'), ('d', 'f'), ('e', 'g'), ('f'
, 'h'), ('g', 'i'), ('h', 'j'), ('i', 'k'), ('j', 'l'), ('k', 'm'
), ('l', 'n'), ('m', 'o'), ('n', 'p'), ('o', 'q'), ('p', 'r'), (
'q', 's'), ('r', 't'), ('s', 'u'), ('t', 'v'), ('u', 'w'), ('v',
'x'), ('w', 'y'), ('x', 'z'), ('y', 'a'), ('z', 'b'), (',', ',')
, ('.', '.'), (' ', ' '), ("'", "'"), ('(', '('), (')', ')')]
14
Level 1
Next Level
As hinted, apply the same function on the url( map ), we get ocr .
>>> "map".translate(str.maketrans("abcdefghijklmnopqrstuvwxyz",
"cdefghijklmnopqrstuvwxyzab"))
'ocr'
http://www.pythonchallenge.com/pc/def/ocr.html
Python 2 to Python 3
In Python 2, maketrans() is a method in string module, so you need to
import it first:
import string
table = string.maketrans("from", "to")
15
Level 1
16
Level 2
Problem
recognize the characters. maybe they are in the book, but MAYBE they are in
the page source.
Right click and select "View Page Source":
17
Level 2
Solution
Load Data
You can manually copy-and-paste the text to a file( resources/level2.txt in
source code), then read from it:
>>> data = open('resources/level2.txt').read()
Read More
More about Python 3 - IO
Or extract the text from HTML directly. First load raw html source coding using
urllib.request :
18
Level 2
Then extract the comment blocks in html. Note that by default dot does not match
\n , so we need to use re .DOTALL flag.
>>> import re
>>> comments = re.findall("<!--(.*?)-->", html, re.DOTALL)
The pattern <!--(.*)--> will capture all blocks inside <!-- and --> . We
only care about the last part, so
>>> data = comments[-1]
Level 2
If you are having a hard time to guess the meaning:
>>> import re
>>> "".join(re.findall("[A-Za-z]", data))
'equality'
result:
equality
Next Level
http://www.pythonchallenge.com/pc/def/equality.html
20
Level 3
Problem
21
Level 3
Hmm, shall we find all segments of the pattern AAAbCCC ?
Solution
Step 1: Load Data
Similar to level 2, You can manually copy-and-paste the text to a
file( resources/level3.txt in source code), then read from it:
>>> data = open('resources/level3.txt').read()
22
Level 3
[^A-Z]+[A-Z]{3}([a-z])[A-Z]{3}[^A-Z]+ : ...and we only care about the
lower case
Let's see what we get:
>>> re.findall("[^A-Z]+[A-Z]{3}([a-z])[A-Z]{3}[^A-Z]+", data)
['l', 'i', 'n', 'k', 'e', 'd', 'l', 'i', 's', 't']
Next Level
http://www.pythonchallenge.com/pc/def/linkedlist.html
The page will redirect you to linkedlist.php
http://www.pythonchallenge.com/pc/def/linkedlist.php
Further Readings
23
Level 3
Python 3 - RegEx
24
Level 4
Problem
Change the url with the new number and another number will be given.
Solution
25
Level 4
First let's try to mimic the manual process we just tried:
>>> uri = "http://www.pythonchallenge.com/pc/def/linkedlist.php?
nothing=%s"
>>> num = "12345"
>>> content = urlopen(uri % num).read().decode()
>>> content
'and the next nothing is 44827'
Note .group(0) will return the whole text that matches the pattern, while the
captured segments start from .group (1)
>>> match.group(0)
'and the next nothing is 44827'
>>> match.group(1)
'72198'
To automate this process, let's use a while loop, which stops when there's no
match:
26
Level 4
And re-run:
and the next nothing is 81226
and the next nothing is 4256
and the next nothing is 62734
and the next nothing is 25666
...
There maybe misleading numbers in the
text. One example is 82683. Look only for the next nothing and t
he next nothing is 63579
...
peak.html
27
Level 4
Note that if you use pattern.match() instead of pattern.search() it would
fail, since .match() is looking for a match starting from the very beginning,
while there's one "misleading" line in the text.
Finally we have the answer: peak.html
Result
peak.html
Next Level
http://www.pythonchallenge.com/pc/def/peak.html
Python 2 to Python 3
28
Level 4
Python 2's urllib and urllib2 are combined as the new urllib
29
Level 5
Problem
pronounce it
Page Source:
<peakhell src="banner.p"/>
<!-- peak hell sounds familiar ? -->
30
Level 5
Solution
Let's print out the raw data:
>>> from urllib.request import urlopen
>>> raw = urlopen("http://www.pythonchallenge.com/pc/def/banner.
p").read()
>>> raw
b"(lp0\n(lp1\n(S' '\np2\nI95\ntp3\naa..."
Normally plain text can be encoded as utf-8 or some other form, once we call
.decode() it will reveal it self, however this one is tough:
>>> raw.decode()
"(lp0\n(lp1\n(S' '\np2\nI95\ntp3\naa..."
31
Level 5
', 3), ('#', 4), (' ', 4), ('#', 5), (' ', 4), ('#', 4), (' ', 2
), ('#', 5), (' ', 4), ('#', 4), (' ', 3), ('#', 3), (' ', 5), (
'#', 3), (' ', 3), ('#', 4), (' ', 1)], [(' ', 1), ('#', 3), (' '
, 11), ('#', 4), (' ', 5), ('#', 4), (' ', 3), ('#', 3), (' ', 4
), ('#', 3), (' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), (
'#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 3), (' ', 6), ('#',
4), (' ', 2), ('#', 4), (' ', 1)], [(' ', 1), ('#', 3), (' ', 11
), ('#', 4), (' ', 5), ('#', 4), (' ', 10), ('#', 3), (' ', 4), (
'#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#',
4), (' ', 2), ('#', 3), (' ', 7), ('#', 3), (' ', 2), ('#', 4), (
' ', 1)], [('#', 4), (' ', 11), ('#', 4), (' ', 5), ('#', 4), ('
', 5), ('#', 2), (' ', 3), ('#', 3), (' ', 4), ('#', 4), (' ', 5
), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 1), (
'#', 4), (' ', 7), ('#', 3), (' ', 2), ('#', 4), (' ', 1)], [('#'
, 4), (' ', 11), ('#', 4), (' ', 5), ('#', 4), (' ', 3), ('#', 10
), (' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (
' ', 5), ('#', 4), (' ', 1), ('#', 14), (' ', 2), ('#', 4), (' '
, 1)], [('#', 4), (' ', 11), ('#', 4), (' ', 5), ('#', 4), (' ',
2), ('#', 3), (' ', 4), ('#', 4), (' ', 4), ('#', 4), (' ', 5), (
'#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 1), ('#',
4), (' ', 12), ('#', 4), (' ', 1)], [('#', 4), (' ', 11), ('#', 4
), (' ', 5), ('#', 4), (' ', 1), ('#', 4), (' ', 5), ('#', 3), (
' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ',
5), ('#', 4), (' ', 1), ('#', 4), (' ', 12), ('#', 4), (' ', 1)]
, [(' ', 1), ('#', 3), (' ', 11), ('#', 4), (' ', 5), ('#', 4), (
' ', 1), ('#', 4), (' ', 5), ('#', 3), (' ', 4), ('#', 4), (' ',
5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 2), (
'#', 3), (' ', 12), ('#', 4), (' ', 1)], [(' ', 2), ('#', 3), ('
', 6), ('#', 2), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 2
), ('#', 3), (' ', 4), ('#', 4), (' ', 4), ('#', 4), (' ', 5), (
'#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 3), ('#',
3), (' ', 6), ('#', 2), (' ', 3), ('#', 4), (' ', 1)], [(' ', 3)
, ('#', 3), (' ', 4), ('#', 2), (' ', 3), ('#', 4), (' ', 5), ('
#', 4), (' ', 3), ('#', 11), (' ', 3), ('#', 4), (' ', 5), ('#',
4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 4), ('#', 3), (
' ', 4), ('#', 2), (' ', 4), ('#', 4), (' ', 1)], [(' ', 6), ('#'
, 3), (' ', 5), ('#', 6), (' ', 4), ('#', 5), (' ', 4), ('#', 2)
, (' ', 4), ('#', 4), (' ', 1), ('#', 6), (' ', 4), ('#', 11), (
' ', 4), ('#', 5), (' ', 6), ('#', 3), (' ', 6), ('#', 6)], [(' '
, 95)]]
32
Level 5
OK! So data is a list of lists of tuples... It does not look like a banner(the file
name), but more like the result of a simple string compression: convert the
repetitive characters to tuples of (character, number of appearance). This level is
all about serialization and compression, isn't it. Let's unravel the string:
>>> for line in data:
... print("".join([k * v for k, v in line]))
...
#####
#####
####
####
####
####
####
####
####
####
####
####
####
####
####
####
### #### ### ### ##### ### #####
### ### ####
### ## #### ####### ## ### #### ####### ####
####### ### ### ####
### ### ##### #### ### #### ##### #### ####
# #### ### ### ####
### #### #### ### ### #### #### ####
#### ### #### ####
### #### #### ### #### #### ####
#### ### ### ####
#### #### #### ## ### #### #### ####
#### #### ### ####
#### #### #### ########## #### #### ####
33
Level 5
#### ############## ####
#### #### #### ### #### #### #### ####
#### #### ####
#### #### #### #### ### #### #### ####
#### #### ####
### #### #### #### ### #### #### ####
#### ### ####
### ## #### #### ### #### #### #### ####
#### ### ## ####
### ## #### #### ########### #### #### ####
#### ### ## ####
### ###### ##### ## #### ###### ##########
# ##### ### ######
`
Next Level
http://www.pythonchallenge.com/pc/def/channel.html
34
Level 6
Problem
Ok... the image was about "zip", not "pants" or anything under it...
Replace html with zip : http://www.pythonchallenge.com/pc/def/channel.zip
35
Level 6
Unzip it. In readme.txt:
welcome to my zipped list.
hint1: start from 90052
hint2: answer is inside the zip
Solution
>>> import zipfile, re
>>>
>>> f = zipfile.ZipFile("resources/channel.zip")
>>> num = '90052'
>>> while True:
... content = f.read(num + ".txt").decode("utf-8")
... print(content)
... match = re.search("Next nothing is (\d+)", content)
... if match == None:
... break
... num = match.group(1)
...
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.
Level 6
Add a few lines to collect the comments:
>>> num = '90052'
>>> comments = []
>>> while True:
... content = f.read(num + ".txt").decode("utf-8")
... comments.append(f.getinfo(num + ".txt").comment.decode("
utf-8"))
... content
... match = re.search("Next nothing is (\d+)", content)
... if match == None:
... break
... num = match.group(1)
...
>>> print("".join(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 **
** **
****************************************************************
**************************************************************
Level 6
import zipfile, re
f = zipfile.ZipFile("channel.zip")
print(f.read("readme.txt").decode("utf-8"))
num = '90052'
comments = []
while True:
content = f.read(num + ".txt").decode("utf-8")
comments.append(f.getinfo(num + ".txt").comment.decode("utf8"))
print(content)
match = re.search("Next nothing is (\d+)", content)
if match == None:
break
num = match.group(1)
print("".join(comments))
Next Level
http://www.pythonchallenge.com/pc/def/oxygen.html
38
Level 7
Problem
Solution 1: PIL(Pillow)
Python 2 to 3
The original PIL was not ported to Python 3. Use the fork called ``Pillow``
instead
Install Pillow
$ pip3 install pillow
To load an image, one way is to download the image to local manually, then load it
by:
39
Level 7
As you can tell, row has lots of duplicates, since each grey block's width is larger
than 1 pixel. If you do some manual counting, you know it is exactly 7 pixels wide,
this should be the easiest way to de-dup:
40
Level 7
Notice that at the end of the array there are some noises: pixels that are not grey
scale, which have the same value for R, G, and B. We can remove those pixels
>>> ords = [r for r, g, b, a in row if r == g == b]
and since RGB is using a positive number in [0, 255] for each color, we can
assume it represents a ASCII character:
>>> "".join(map(chr, ords))
'smart guy, you made it. the next level is [105, 110, 116, 101,
103, 114, 105, 116, 121]'
Finally:
>>> "".join(map(chr, map(int, nums)))
'integrity'
Solution 2: PyPNG
Alternatively use a package called PyPNG :
pip install pypng
41
Level 7
Next Level
http://www.pythonchallenge.com/pc/def/integrity.html
42
Level 7
Read More
Pillow Documentation
43
Level 8
Problem
44
Level 8
<!-un: 'BZh91AY&SYA\xaf\x82\r\x00\x00\x01\x01\x80\x02\xc0\x02\x00 \
x00!\x9ah3M\x07<]\xc9\x14\xe1BA\x06\xbe\x084'
pw: 'BZh91AY&SY\x94$|\x0e\x00\x00\x00\x81\x00\x03$ \x00!\x9ah3M\
x13<]\xc9\x14\xe1BBP\x91\xf08'
-->
The opposite of "inflate" is... "compress". Do not blame yourself if you do not know
which compression format it is. Here are some clues that it is "bzip2"...
.magic:16 = 'BZ' signature/magic number .version:8 = 'h' for Bzip2 ('H'uffman
coding), '0' for Bzip1 (deprecated) .hundred_k_blocksize:8 = '1'..'9' block-size
100 kB-900 kB (uncompressed)
Solution
Let's decompress it:
>>> import bz2
>>> bz2.decompress('BZh91AY&SYA\xaf\x82\r\x00\x00\x01\x01\x80\x0
2\xc0\x02\x00 \x00!\x9ah3M\x07<]\xc9\x14\xe1BA\x06\xbe\x084')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.5/bz2.py", line 348, in decompress
res = decomp.decompress(data)
TypeError: a bytes-like object is required, not 'str'
That does not work... .decompress() expects some bytes , not string
>>> bz2.decompress(b'BZh91AY&SYA\xaf\x82\r\x00\x00\x01\x01\x80\x
02\xc0\x02\x00 \x00!\x9ah3M\x07<]\xc9\x14\xe1BA\x06\xbe\x084')
b'huge'
>>> bz2.decompress(b'BZh91AY&SY\x94$|\x0e\x00\x00\x00\x81\x00\x0
3$ \x00!\x9ah3M\x13<]\xc9\x14\xe1BBP\x91\xf08')
b'file'
45
Level 8
Next Level
Click the fly(or the link in page source): ../return/good.html , and fill in
username( huge ) and password( file )
http://www.pythonchallenge.com/pc/return/good.html
46
Level 9
Problem
In page source:
<!-first+second=?
first:
146,399,163,403,170,393,169,391,166,386,170,381,170,371,170,355,
169,346,167,335,170,329,170,320,170,
47
Level 9
310,171,301,173,290,178,289,182,287,188,286,190,286,192,291,194,
296,195,305,194,307,191,312,190,316,
190,321,192,331,193,338,196,341,197,346,199,352,198,360,197,366,
197,373,196,380,197,383,196,387,192,
389,191,392,190,396,189,400,194,401,201,402,208,403,213,402,216,
401,219,397,219,393,216,390,215,385,
215,379,213,373,213,365,212,360,210,353,210,347,212,338,213,329,
214,319,215,311,215,306,216,296,218,
290,221,283,225,282,233,284,238,287,243,290,250,291,255,294,261,
293,265,291,271,291,273,289,278,287,
279,285,281,280,284,278,284,276,287,277,289,283,291,286,294,291,
296,295,299,300,301,304,304,320,305,
327,306,332,307,341,306,349,303,354,301,364,301,371,297,375,292,
384,291,386,302,393,324,391,333,387,
328,375,329,367,329,353,330,341,331,328,336,319,338,310,341,304,
341,285,341,278,343,269,344,262,346,
259,346,251,349,259,349,264,349,273,349,280,349,288,349,295,349,
298,354,293,356,286,354,279,352,268,
352,257,351,249,350,234,351,211,352,197,354,185,353,171,351,154,
348,147,342,137,339,132,330,122,327,
120,314,116,304,117,293,118,284,118,281,122,275,128,265,129,257,
131,244,133,239,134,228,136,221,137,
214,138,209,135,201,132,192,130,184,131,175,129,170,131,159,134,
157,134,160,130,170,125,176,114,176,
102,173,103,172,108,171,111,163,115,156,116,149,117,142,116,136,
115,129,115,124,115,120,115,115,117,
113,120,109,122,102,122,100,121,95,121,89,115,87,110,82,109,84,1
18,89,123,93,129,100,130,108,132,110,
133,110,136,107,138,105,140,95,138,86,141,79,149,77,155,81,162,9
0,165,97,167,99,171,109,171,107,161,
111,156,113,170,115,185,118,208,117,223,121,239,128,251,133,259,
136,266,139,276,143,290,148,310,151,
332,155,348,156,353,153,366,149,379,147,394,146,399
second:
156,141,165,135,169,131,176,130,187,134,191,140,191,146,186,150,
179,155,175,157,168,157,163,157,159,
157,158,164,159,175,159,181,157,191,154,197,153,205,153,210,152,
212,147,215,146,218,143,220,132,220,
125,217,119,209,116,196,115,185,114,172,114,167,112,161,109,165,
48
Level 9
107,170,99,171,97,167,89,164,81,162,
77,155,81,148,87,140,96,138,105,141,110,136,111,126,113,129,118,
117,128,114,137,115,146,114,155,115,
158,121,157,128,156,134,157,136,156,136
-->
first and second have different lengths, so it is not simply adding up the two
arrays. The image has some dots, maybe we should just connect the dots...
Solution
Copy and paste...
>>> first = [
... 146,399,163,403,170,393,169,391,166,386,170,381,170,371,170,
355,169,346,167,335,170,329,170,320,170,
... 310,171,301,173,290,178,289,182,287,188,286,190,286,192,291,
194,296,195,305,194,307,191,312,190,316,
... 190,321,192,331,193,338,196,341,197,346,199,352,198,360,197,
366,197,373,196,380,197,383,196,387,192,
... 389,191,392,190,396,189,400,194,401,201,402,208,403,213,402,
216,401,219,397,219,393,216,390,215,385,
... 215,379,213,373,213,365,212,360,210,353,210,347,212,338,213,
329,214,319,215,311,215,306,216,296,218,
... 290,221,283,225,282,233,284,238,287,243,290,250,291,255,294,
261,293,265,291,271,291,273,289,278,287,
... 279,285,281,280,284,278,284,276,287,277,289,283,291,286,294,
291,296,295,299,300,301,304,304,320,305,
... 327,306,332,307,341,306,349,303,354,301,364,301,371,297,375,
292,384,291,386,302,393,324,391,333,387,
... 328,375,329,367,329,353,330,341,331,328,336,319,338,310,341,
304,341,285,341,278,343,269,344,262,346,
... 259,346,251,349,259,349,264,349,273,349,280,349,288,349,295,
349,298,354,293,356,286,354,279,352,268,
... 352,257,351,249,350,234,351,211,352,197,354,185,353,171,351,
154,348,147,342,137,339,132,330,122,327,
... 120,314,116,304,117,293,118,284,118,281,122,275,128,265,129,
49
Level 9
257,131,244,133,239,134,228,136,221,137,
... 214,138,209,135,201,132,192,130,184,131,175,129,170,131,159,
134,157,134,160,130,170,125,176,114,176,
... 102,173,103,172,108,171,111,163,115,156,116,149,117,142,116,
136,115,129,115,124,115,120,115,115,117,
... 113,120,109,122,102,122,100,121,95,121,89,115,87,110,82,109,
84,118,89,123,93,129,100,130,108,132,110,
... 133,110,136,107,138,105,140,95,138,86,141,79,149,77,155,81,1
62,90,165,97,167,99,171,109,171,107,161,
... 111,156,113,170,115,185,118,208,117,223,121,239,128,251,133,
259,136,266,139,276,143,290,148,310,151,
... 332,155,348,156,353,153,366,149,379,147,394,146,399]
>>> second = [156,141,165,135,169,131,176,130,187,134,191,140,191
,146,186,150,179,155,175,157,168,157,163,157,159,
... 157,158,164,159,175,159,181,157,191,154,197,153,205,153,210,
152,212,147,215,146,218,143,220,132,220,
... 125,217,119,209,116,196,115,185,114,172,114,167,112,161,109,
165,107,170,99,171,97,167,89,164,81,162,
... 77,155,81,148,87,140,96,138,105,141,110,136,111,126,113,129,
118,117,128,114,137,115,146,114,155,115,
... 158,121,157,128,156,134,157,136,156,136]
Use PIL(pillow)
>>> from PIL import Image,ImageDraw
>>> im = Image.new('RGB', (500,500))
>>> draw = ImageDraw.Draw(im)
>>> draw.polygon(first, fill='white')
>>> draw.polygon(second, fill='white')
>>> im.show()
50
Level 9
Next Level
http://www.pythonchallenge.com/pc/return/bull.html
51
Level 10
Problem
len(a[30]) = ?
By clicking the image:
a = [1, 11, 21, 1211, 111221,
A look-and-say sequence
52
Level 10
Solution 1
This is a naive solution, just look, and say, assemble the string while we are
counting.
a = '1'
b = ''
for i in range(0, 30):
j = 0
k = 0
while j < len(a):
while k < len(a) and a[k] == a[j]: k += 1
b += str(k-j) + a[j]
j = k
print b
a = b
b = ''
print len(a)
Solution 2
Python can do much better. We can use regular expression to find the (number,
length) pairs
>>> import re
>>> re.findall(r"(\d)(\1*)", "111221")
[('1', '11'), ('2', '2'), ('1', '')]
Note that the pattern is a raw string( r"..." ), which means backslash( \ ) does
not need to be escaped. It is equivalent to
>>> re.findall("(\\d)(\\1*)", "111221")
The result tuples are in the form: (first appearance, following appearance), so from
the first one we get the number, and the second one we get the length(remember
to +1)
53
Level 10
Solution 3
Similar to Solution 2, but we are using itertools.groupby() instead of regular
expression to find the (number, length) pairs:
>>> "".join([str(len(list(j))) + i for i,j in itertools.groupby(
"1211")])
'111221'
54
Level 10
Solution 4
This is not recommend, but it is a cool one-liner solution. Do not sacrifice clarity
for coolness in the real world projects!
>>> from itertools import groupby
>>> from functools import reduce
>>> len(reduce(lambda x, n:reduce(lambda a, b: a + str(len(list(
b[1]))) + b[0], groupby(x), ""), range(30), "1"))
5808
2 nested reduce() , the outer one simply let it run for 30 times, and set the initial
value 1 for x ; the inner one does exactly the same as in Solution 3.
Again, whether this bothers you or not, do not code anything that need you
extensive explanations.
Next Level
http://www.pythonchallenge.com/pc/return/5808.html
55
Level 10
56
Level 11
Problem
Solution
The only clue is the title, which implies that we need to split the image by
odd/even:
57
Level 11
Next Level
http://www.pythonchallenge.com/pc/return/evil.html
58
Level 12
Problem
Checking the source, the image is named as evil1.jpg . Try evil2 and you
will see:
http://www.pythonchallenge.com/pc/return/evil2.jpg
59
Level 12
60
Level 12
Really? "no more evils"? Let's try evil4.jpg. Depend on your browser, you may see
nothing or an error message
The image "http://www.pythonchallenge.com/pc/return/evil4.jpg" cannot be
displayed because it contains errors.
But, it is not 404! Let's take a closer look:
$ curl -u huge:file http://www.pythonchallenge.com/pc/return/evi
l4.jpg
Bert is evil! go back!
Solution
It is hard to tell what's going on inside the file.
61
Level 12
Back to the problem's image, someone is dealing the cards into 5 stacks, and all
the cards are ... 5.
>>> len(data)
67575
Let's try to split the data into 5, but "dealing" the bytes instead of cards...
>>> for i in range(5):
... open('%d.jpg' % i ,'wb').write(data[i::5])
Open the generated 0.jpg through 4.jpg , you should see dis , pro ,
port , tional
62
Level 12
63
Level 12
Next Level
http://www.pythonchallenge.com/pc/return/disproportional.html
64
Level 13
Problem
65
Level 13
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value>
<int>105</int>
</value>
</member>
<member>
<name>faultString</name>
<value>
<string>
XML error: Invalid document end at line 1, column
1
</string>
</value>
</member>
</struct>
</value>
</fault>
</methodResponse>
Solution
We can use xmlrpc module to talk to it:
>>> import xmlrpc.client
>>> conn = xmlrpc.client.ServerProxy("http://www.pythonchallenge
.com/pc/phonebook.php")
>>> conn
<ServerProxy for www.pythonchallenge.com/pc/phonebook.php>
>>> conn.system.listMethods()
['phone', 'system.listMethods', 'system.methodHelp', 'system.met
hodSignature', 'system.multicall', 'system.getCapabilities']
66
Level 13
phone seems to be the method we should call. Get more info on how to use it:
>>> conn.system.methodHelp("phone")
'Returns the phone of a person'
>>> conn.system.methodSignature("phone")
[['string', 'string']]
So it takes a string and returns a string, the input should be the name and the
output should be the number:
>>> conn.phone("Bert")
'555-ITALY'
If you do not know, 555 basically means "fake phone numbers" in US... The key
is "italy".
Next Level
http://www.pythonchallenge.com/pc/return/italy.html
67
Level 14
Problem Link
http://www.pythonchallenge.com/pc/return/italy.html
Username: huge
Password: file
Clues
Clue 1
In HTML source code:
68
Level 14
Clue 2
Title of the HTML:
walk around
Clue 3
The image of the problem: we are looking at(for) something spiral!
Exploration
Do not be fooled by that barcode-like image, it appears to be a square, that is
because in HTML both the width and height are set as 100.
>>> from PIL import Image
>>> im = Image.open('../images/wire.png')
>>> im.size
(10000, 1)
69
Level 14
Solution
from PIL import Image
im = Image.open('wire.png')
delta = [(1,0),(0,1),(-1,0),(0,-1)]
out = Image.new('RGB', [100,100])
x,y,p = -1,0,0
d = 200
while d/2>0:
for v in delta:
steps = d // 2
for s in range(steps):
x, y = x + v[0], y + v[1]
out.putpixel((x, y),im.getpixel((p,0)))
p += 1
d -= 1
out.save('level_14_result.jpg')
It's a cat!
Next Level
http://www.pythonchallenge.com/pc/return/cat.html
and its name is uzi. you'll hear from him later.
http://www.pythonchallenge.com/pc/return/uzi.html
70
Level 15
Problem Link
Link: http://www.pythonchallenge.com/pc/return/uzi.html
Username: huge
Password: file
Clues
Clue 1
There's a burnt hole on the calendar, it must be year 1xx6.
71
Level 15
Clue 2
That year's Jan 1 is a Thursday.
Clue 3
It was a leap year, since Feb 29 is on the calendar.
Clue 4
We are looking for Jan 26.
Clue 5
In HTML source code:
<!-- he ain't the youngest, he is the second -->
Clue 6
Title: whom?
Clue 7
In HTML source code:
<!-- todo: buy flowers for tomorrow -->
Exploration
So we are looking for a person, who's related to that particular date, and he is not
the youngest...
The key is to find what year it was. We can filter the years between 1006 and
1996 by those clues.
72
Level 15
First the leap year. Is 1006 a leap year?
>>> 1006 / 4
251.5
From clue 5:
he ain't the youngest, he is the second
1976 must be the youngest, so 1756 is the second youngest... what is special with
1756-01-26? Nothing. But remember the last clue:
todo: buy flowers for tomorrow
And... 1756-01-27 is the birthday of Mozart...
73
Level 15
Solution
Alternatively we can use canlendar.isleap() to detect leap year, which
makes it more clear. Check out the full solution:
import datetime, calendar
for year in range(1006,1996,10):
d = datetime.date(year, 1, 26)
if d.isoweekday() == 1 & calendar.isleap(year):
print(d)
Output
1176-01-26
1356-01-26
1576-01-26
1756-01-26
1976-01-26
Next Level
http://www.pythonchallenge.com/pc/return/mozart.html
74
Level 16
Problem Link
Link: http://www.pythonchallenge.com/pc/return/mozart.html
Username: huge
Password: file
Clues
Clue 1
Page Title:
let me get this straight
75
Level 16
Clue 2
Image: There are pink segments, looks like they have the same length.
Exploration
Sounds like we need to align the pink segments. But how do you define "pink"
So value 60 appears 29448 times, let's see if it is pink. We can make a copy of the
current image(to use the same palette), and paint all the pixels as 60:
>>> tmp = image.copy()
>>> tmp.frombytes(bytes([60] * (tmp.height * tmp.width)))
>>> tmp.show()
76
Level 16
77
Level 16
We are using np.array(image) to load image data, alternatively you can use
list(image.getdata()) , however you will get a one-dimension array, so you
78
Level 16
Solution
Solution 1
from PIL import Image, ImageChops
import numpy as np
image = Image.open("mozart.gif")
shifted = [bytes(np.roll(row, -row.tolist().index(195)).tolist()
) for row in np.array(image)]
Image.frombytes(image.mode, image.size, b"".join(shifted)).show(
)
79
Level 16
Solution 2
from PIL import Image, ImageChops
image = Image.open("mozart.gif")
for y in range(image.size[1]):
box = 0, y, image.size[0], y + 1
row = image.crop(box)
bytes = row.tobytes()
i = bytes.index(195)
row = ImageChops.offset(row, -i)
image.paste(row, box)
image.save("level16-result.gif")
Result: romance!
Next Level
http://www.pythonchallenge.com/pc/return/romance.html
80
Level 17
Problem Link
Link: http://www.pythonchallenge.com/pc/return/romance.html
Username: huge
Password: file
Clues
Clue 1
Image: it is named cookies
Clue 2
81
Level 17
There's an embedded image. Looks familiar? It's from Level 4.
Solution
Part 1:
from urllib.request import urlopen
from urllib.parse import unquote_plus, unquote_to_bytes
import re, bz2
num = '12345'
info = ''
while(True):
h = urlopen('http://www.pythonchallenge.com/pc/def/linkedlis
t.php?busynothing='+num)
raw = h.read().decode("utf-8")
print(raw)
cookie = h.getheader("Set-Cookie")
info += re.search('info=(.*?);', cookie).group(1)
match = re.search('the next busynothing is (\d+)', raw)
if match == None:
break
else:
num = match.group(1)
res = unquote_to_bytes(info.replace("+", " "))
print(res)
print(bz2.decompress(res).decode())
Output:
82
Level 17
...
and the next busynothing is 96070
and the next busynothing is 83051
that's it.
b'BZh91AY&SY\x94:\xe2I\x00\x00!\x19\x80P\x81\x11\x00\xafg\x9e\xa
0 \x00hE=M\xb5#\xd0\xd4\xd1\xe2\x8d\x06\xa9\xfa&S\xd4\xd3!\xa1\x
eai7h\x9b\x9a+\xbf`"\xc5WX\xe1\xadL\x80\xe8V<\xc6\xa8\xdbH&32\x1
8\xa8x\x01\x08!\x8dS\x0b\xc8\xaf\x96KO\xca2\xb0\xf1\xbd\x1du\xa0
\x86\x05\x92s\xb0\x92\xc4Bc\xf1w$S\x85\t\tC\xae$\x90'
Part 2:
from xmlrpc.client import ServerProxy
conn = ServerProxy("http://www.pythonchallenge.com/pc/phonebook.
php")
print(conn.phone("Leopold"))
555-VIOLIN
Visit http://www.pythonchallenge.com/pc/return/violin.html
no! i mean yes! but ../stuff/violin.php.
Part 3:
83
Level 17
<html>
<head>
<title>it's me. what do you want?</title>
<link rel="stylesheet" type="text/css" href="../style.css">
</head>
<body>
<br><br>
<center><font color="gold">
<img src="leopold.jpg" border="0"/>
<br><br>
oh well, don't you dare to forget the balloons.</font>
</body>
</html>
Next Level
http://www.pythonchallenge.com/pc/stuff/balloons.html
redirect to
http://www.pythonchallenge.com/pc/return/balloons.html
84
Level 18
Problem
Solution
The difference is "brightness"... so go to
http://www.pythonchallenge.com/pc/return/brightness.html
In HTML source:
<!-- maybe consider deltas.gz -->
Download: http://www.pythonchallenge.com/pc/return/deltas.gz
>>> print(gzip.open("deltas.gz").read().decode())
85
Level 18
You will see the data consists roughly two columns.
import gzip, difflib
data = gzip.open("deltas.gz")
d1, d2 = [], []
for line in data:
d1.append(line[:53].decode()+"\n")
d2.append(line[56:].decode())
86
Level 18
f1.png : butter
f2.png : fly
Next Level
http://www.pythonchallenge.com/pc/hex/bin.html
username: butter
password: fly
87
Level 19
Problem
Solution
88
Level 19
w = wave.open('indian.wav', 'rb')
h = wave.open("result.wav", "wb")
print(w.getnchannels())
print(w.getsampwidth())
print(w.getframerate())
h.setnchannels(w.getnchannels())
h.setsampwidth(w.getsampwidth()//2)
h.setframerate(w.getframerate()*2)
frames = w.readframes(w.getnframes())
wave.big_endiana = 1
h.writeframes(frames)
h.close()
Next Level
http://www.pythonchallenge.com/pc/hex/idiot2.html
89
Level 20
Problem
Solution
90
Level 20
91
Level 20
So now the content between 30203 and 30236 is served, which is "Why don't you
respect my privacy?"; continue for a few iterations:
pattern = re.compile('bytes (\d+)-(\d+)/(\d+)')
content_range = response.headers['content-range']
(start, end, length) = pattern.search(content_range).groups()
while True:
try:
request.headers['Range'] = 'bytes=%i-' % (int(end) + 1)
response = urllib.request.urlopen(request)
print(response.read().decode())
print(response.headers)
(start, end, length) = pattern.search(response.headers['
content-range']).groups()
except:
break
It prints:
Why don't you respect my privacy?
we can go on in this way for really long time.
stop this!
invader! invader!
ok, invader. you are inside now.
92
Level 20
Result:
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-Range: bytes 2123456744-2123456788/2123456789
Connection: close
Transfer-Encoding: chunked
Server: lighttpd/1.4.35
esrever ni emankcin wen ruoy si drowssap eht
The content is reversed: "the password is your new nickname in reverse". The
"nickname" is "invader", so password is "redavni".
Now "reverse" the search:
request.headers['Range'] = 'bytes=2123456743-'
response = urllib.request.urlopen(request)
print(response.headers)
print(response.read().decode())
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-Range: bytes 2123456712-2123456743/2123456789
Connection: close
Transfer-Encoding: chunked
Date: Mon, 02 May 2016 18:12:45 GMT
Server: lighttpd/1.4.35
93
Level 20
Then save it as a zip file:
request.headers['Range'] = 'bytes=1152983631-'
response = urllib.request.urlopen(request)
with open("level21.zip", "wb") as f:
f.write(response.read())
Next Level
Inside the zip file
94
Level 21
Solution
import zlib, bz2
with open("package.pack", "rb") as f:
data = f.read()
while True:
if data.startswith(b'x\x9c'):
data = zlib.decompress(data)
elif data.startswith(b'BZh'):
data = bz2.decompress(data)
elif data.endswith(b'\x9cx'):
data = data[::-1]
else:
break
print(data)
Result:
b'sgol ruoy ta kool'
Add logging:
95
Level 21
96
Level 21
Next Level
http://www.pythonchallenge.com/pc/hex/copper.html
97
Level 22
Problem
Solution
98
Level 22
Result: bonus
Next Level
http://www.pythonchallenge.com/pc/hex/bonus.html
99
Level 23
Problem
Solution
this is a special module in Python:
100
Level 23
101
Level 23
>>> print(this.s)
Gur Mra bs Clguba, ol Gvz Crgref
Ornhgvshy vf orggre guna htyl.
Rkcyvpvg vf orggre guna vzcyvpvg.
Fvzcyr vf orggre guna pbzcyrk.
Pbzcyrk vf orggre guna pbzcyvpngrq.
Syng vf orggre guna arfgrq.
Fcnefr vf orggre guna qrafr.
Ernqnovyvgl pbhagf.
Fcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.
Nygubhtu cenpgvpnyvgl orngf chevgl.
Reebef fubhyq arire cnff fvyragyl.
Hayrff rkcyvpvgyl fvyraprq.
Va gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.
Gurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb q
b vg.
Nygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgp
u.
Abj vf orggre guna arire.
Nygubhtu arire vf bsgra orggre guna *evtug* abj.
Vs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.
Vs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.
Anzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!
102
Level 23
103
Level 23
>>> this.d
{'n': 'a', 'J': 'W', 'o': 'b', 'r': 'e', 'T': 'G', 'K': 'X', 'v'
: 'i', 'H': 'U', 'L': 'Y', 'q': 'd', 'w': 'j', 'O': 'B', 'e': 'r'
, 'S': 'F', 'l': 'y', 'X': 'K', 'I': 'V', 'a': 'n', 'Z': 'M', 'G'
: 'T', 'i': 'v', 'f': 's', 'u': 'h', 'h': 'u', 'N': 'A', 'R': 'E'
, 'P': 'C', 'M': 'Z', 'C': 'P', 'b': 'o', 'U': 'H', 'A': 'N', 'B'
: 'O', 'W': 'J', 'D': 'Q', 'k': 'x', 'c': 'p', 'x': 'k', 'm': 'z'
, 'F': 'S', 'V': 'I', 'E': 'R', 'Q': 'D', 'p': 'c', 'g': 't', 'Y'
: 'L', 'j': 'w', 'y': 'l', 's': 'f', 't': 'g', 'z': 'm', 'd': 'q'
}
104
Level 23
Use this to decode the message:
>>> s = 'va gur snpr bs jung?'
>>> print("".join([this.d.get(c, c) for c in s]))
in the face of what?
Next Level
http://www.pythonchallenge.com/pc/hex/ambiguity.html
105
Level 24
Problem
Solution
106
Level 24
Load the image:
>>> from PIL import Image
>>> maze = Image.open("maze.png")
>>> w, h = maze.size
There's only one black pixel( (0, 0, 0, 255) ), others are white( (255, 255,
255, 255) ) or grey(the upper left corner square with the number of the level), so
there's only one black pixel at (1, h - 1) , that would be the exit point.
By printing out the "inner" pixels you may notice that the non-white points all look
like (x, 0, 0, 255) , where x would vary. That is the data we need to
collect.
A BFS would find the shortest path:
107
Level 24
Next Level
http://www.pythonchallenge.com/pc/hex/lake.html
108
Level 24
109
Level 25
Problem
Solution
To download a wav file, use wget with authentication:
$ wget --user butter --password fly
http://www.pythonchallenge.com/pc/hex/lake1.wav
To download all the wav files:
110
Level 25
Next Level
www.pythonchallenge.com/pc/hex/decent.html
111
Level 26
Problem
Solution
Send the email to [email protected] and get the response:
112
Level 26
From: [email protected] Subject: Re: sorry Date:
Never mind that.
Have you found my broken zip?
md5: bbb8b499a0eef99b52c7f13f4e78c24b
Can you believe what one mistake can lead to?
As indicated there's only "one mistake". Try to modify the data and check by md5
code.
import hashlib
def search_and_save():
for i in range(len(data)):
for j in range(256):
newData = data[:i] + bytes([j]) + data[i + 1:]
if hashlib.md5(newData).hexdigest() == md5code:
open('repaired.zip', 'wb').write(newData)
return
md5code = 'bbb8b499a0eef99b52c7f13f4e78c24b'
data = open('maze/mybroken.zip', 'rb').read()
search_and_save()
Next Level
http://www.pythonchallenge.com/pc/hex/speedboat.html
Python 2 to 3
md5 module is deprecated, use hashlib.md5()
113
Level 26
open() without explicitly specifying rb will use the default utf-8 codec
for decoding.
114
Level 27
Problem
Solution
115
Level 27
Full Solution
116
Level 27
palette = im.getpalette()[::3]
table = bytes.maketrans(bytes([i for i in range(256)]), bytes(pa
lette))
raw = im.tobytes()
trans = raw.translate(table)
zipped = list(zip(raw[1:], trans[:-1]))
diff = list(filter(lambda p: p[0] != p[1], zipped))
indices = [i for i,p in enumerate(zipped) if p[0] != p[1]]
im2 = Image.new("RGB", im.size)
colors = [(255, 255, 255)] * len(raw)
for i in indices:
colors[i] = (0, 0, 0)
im2.putdata(colors)
#im2.show()
Result:
117
Level 27
Well, this level needs to be updated, since exec and print are not keywords
in Python 3. The only two words left are repeat and switch
Next Level
http://www.pythonchallenge.com/pc/ring/bell.html
username: repeat
password: switch
118
Level 28
Problem
Solution
http://www.pythonchallenge.com/pc/ring/green.html
yes! green!
119
Level 28
Result
whodunnit().split()[0] ?
The creator of Python is Guido van Rossum, so the final answer is "guido"
Next Level
http://www.pythonchallenge.com/pc/ring/guido.html
120
Level 29
Problem
Solution
Notice that there "silent" empty lines in the html source code. And the lines are of
different lengths. Convert the lengths to bytes and decompress by bz2:
121
Level 29
Next Level
http://www.pythonchallenge.com/pc/ring/yankeedoodle.html
122
Level 30
Problem
Solution
$ wget --user repeat --password switch
http://www.pythonchallenge.com/pc/ring/yankeedoodle.csv
123
Level 30
keyword: grandpa
Next Level
124
Level 30
http://www.pythonchallenge.com/pc/ring/grandpa.html
125
Level 31
Problem
126
Level 31
127
Level 31
In page source:
<img src="mandelbrot.gif" border="0">
<window left="0.34" top="0.57" width="0.036" height="0.027"/>
<option iterations="128"/>
Solution
It is a image of the Mandelbrot set.
The Mandelbrot set is the set of complex numbers c for which the function f(z)
= z^2 + c does not diverge when iterated from z = 0, i.e., for which the
sequence f(0), f(f(0)), etc., remains bounded in absolute value.
To slightly translate this into English: every pixel in the 2-d image (x, y) ,
uniquely represents a complex number c , we let z = 0 + 0j , then repeatedly
calculate z = z * z + c , if z is always within a range(not going to infinity),
128
Level 31
we light this pixel up, otherwise we mark it as dark. Actually we check at which
iteration it starts to diverge, and set color to that number of iteration.
In page source we are given 4 number: left, top, width, height, that is the bound of
our calculation. Suppose the image we are going to produce has width w and
height h , then x should be from 0 to w - 1 , and y should be from 0
to h - 1 . The real part of the c can be computed by left + x * width /
w , and imaginary part is bottom + y * height / h
129
Level 31
Extra Links
https://en.wikipedia.org/wiki/Arecibo_message
130
Level 32
Problem
Solution
131
Level 32
import time
class Seg:
def __init__(self, length):
self.length = length
self.placements = []
def __repr__(self):
return '<Seg:len=' + str(self.length) + ',placements=' +
str(self.placements) + '>'
class Bar:
def __init__(self, axis, index, segs, length):
self.segs = segs
self.complete = False
self.dirty = False
self.axis = axis
self.index = index
self.length = length
self.full_space = sum([seg.length for seg in self.segs])
+ len(self.segs) - 1
def is_full(self):
return self.full_space == self.length
def __repr__(self):
return '<Bar:axis=' + str(self.axis) + ',index=' + str(s
elf.index) + ',len=' + str(
self.length) + ',full_space=' + str(
self.full_space) + ',segs=' + str(self.segs) + ',dir
ty=' + str(self.dirty) + '>'
def __lt__(self, other):
return self.index - other.index
def load():
132
Level 32
with open("up.txt") as f:
lines = f.readlines()
lines = [line.strip() for line in lines if (not line.sta
rtswith('#')) and len(line.strip()) != 0]
raw = [list(map(int, line.split())) for line in lines]
assert sum(raw[0]) == len(raw) - 1
return raw[1:raw[0][0] + 1], raw[raw[0][0] + 1:]
def print_board(board):
m = {1: '#', 0: ' ', None: '?'}
print("\n".join([''.join([m[ele] for ele in row]) for row in
board]))
def calc_space(segs):
return sum([seg.length for seg in segs]) + len(segs) - 1
def calc_placement(bars):
for bar in bars:
for i in range(len(bar.segs)):
seg = bar.segs[i]
start = calc_space(bar.segs[:i]) + 1
end = bar.length - calc_space(bar.segs[i + 1:]) - se
g.length
seg.placements = list(range(start, end))
133
Level 32
for seg in bar.segs:
for i in range(seg.placements[-1], seg.placements[0]
+ seg.length):
if update_board(board, bar, i, 1):
bars[(1 - bar.axis) * h + i].dirty = True
134
Level 32
end = len(board[bar.axis][0])
if i != len(tmp_placements) - 1:
end = tmp_placements[i + 1]
for j in range(placement + seg.length, end):
flags[j] |= 2
prev = placement + seg.length
135
Level 32
check_bar(board, bar, start=placement + seg.length +
1, iseg=iseg + 1, tmp_placements=tmp_placements,
flags=flags)
136
Level 32
ags=flags)
for i in range(len(flags)):
flag = flags[i]
if flag == 1:
if update_board(board, bar, i, 1):
bars[(1 - bar.axis) * h + i].dirty = True
elif flag == 2:
if update_board(board, bar, i, 0):
bars[(1 - bar.axis) * h + i].dirty = True
bar.dirty = False
print_board(board[0])
print(time.process_time())
Next Level
Level 33: http://www.pythonchallenge.com/pc/rock/beer.html
137
Level 33
Problem
Solution
>>> im.size
(138, 138)
>>> im.mode
'L'
>>> list(im.getdata())
[1, 43, 7, 13, 7, 1, 1, 85, 25, 85,...]
>>> im.histogram()
[0, 1532, 232, 0, 0, 0, 0, 963, 189, 0, 0, 0, 0, 724, 329, 0, 0,
0, 0, 549, 243, 0, 0, 0, 0, 144, 424, 0, 0, 0, 0, 119, 328, 0, 0
138
Level 33
, 0, 0, 126, 339, 0, 0, 0, 0, 126, 357, 0, 0, 0, 0, 107, 225, 0,
0, 0, 0, 79, 609, 0, 0, 0, 0, 181, 356, 0, 0, 0, 0, 70, 298, 0, 0
, 0, 0, 23, 164, 0, 0, 0, 0, 26, 354, 0, 0, 0, 0, 47, 341, 0, 0,
0, 0, 139, 257, 0, 0, 0, 0, 104, 505, 0, 0, 0, 0, 192, 224, 0, 0
, 0, 0, 114, 310, 0, 0, 0, 0, 32, 183, 0, 0, 0, 0, 238, 198, 0, 0
, 0, 0, 117, 327, 0, 0, 0, 0, 110, 342, 0, 0, 0, 0, 118, 342, 0,
0, 0, 0, 145, 323, 0, 0, 0, 0, 152, 324, 0, 0, 0, 0, 161, 323, 0
, 0, 0, 0, 175, 317, 0, 0, 0, 0, 183, 317, 0, 0, 0, 0, 171, 337,
0, 0, 0, 0, 198, 318, 0, 0, 0, 0, 241, 283, 0, 0, 0, 0, 1348, 272
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> list(enumerate(im.histogram()))
[(0, 0), (1, 1532), (2, 232), (3, 0), (4, 0), (5, 0), (6, 0), (7
, 963), (8, 189), (9, 0), (10, 0), (11, 0), (12, 0), (13, 724), (
14, 329), (15, 0), (16, 0), (17, 0), (18, 0), (19, 549), (20, 243
), (21, 0), (22, 0), (23, 0), (24, 0), (25, 144), (26, 424), (27
, 0), (28, 0), (29, 0), (30, 0), (31, 119), (32, 328), (33, 0), (
34, 0), (35, 0), (36, 0), (37, 126), (38, 339), (39, 0), (40, 0)
, (41, 0), (42, 0), (43, 126), (44, 357), (45, 0), (46, 0), (47,
0), (48, 0), (49, 107), (50, 225), (51, 0), (52, 0), (53, 0), (54
, 0), (55, 79), (56, 609), (57, 0), (58, 0), (59, 0), (60, 0), (
61, 181), (62, 356), (63, 0), (64, 0), (65, 0), (66, 0), (67, 70
), (68, 298), (69, 0), (70, 0), (71, 0), (72, 0), (73, 23), (74,
164), (75, 0), (76, 0), (77, 0), (78, 0), (79, 26), (80, 354), (
81, 0), (82, 0), (83, 0), (84, 0), (85, 47), (86, 341), (87, 0),
(88, 0), (89, 0), (90, 0), (91, 139), (92, 257), (93, 0), (94, 0
), (95, 0), (96, 0), (97, 104), (98, 505), (99, 0), (100, 0), (1
01, 0), (102, 0), (103, 192), (104, 224), (105, 0), (106, 0), (1
07, 0), (108, 0), (109, 114), (110, 310), (111, 0), (112, 0), (1
13, 0), (114, 0), (115, 32), (116, 183), (117, 0), (118, 0), (119
, 0), (120, 0), (121, 238), (122, 198), (123, 0), (124, 0), (125
, 0), (126, 0), (127, 117), (128, 327), (129, 0), (130, 0), (131
, 0), (132, 0), (133, 110), (134, 342), (135, 0), (136, 0), (137
, 0), (138, 0), (139, 118), (140, 342), (141, 0), (142, 0), (143
, 0), (144, 0), (145, 145), (146, 323), (147, 0), (148, 0), (149
, 0), (150, 0), (151, 152), (152, 324), (153, 0), (154, 0), (155
, 0), (156, 0), (157, 161), (158, 323), (159, 0), (160, 0), (161
, 0), (162, 0), (163, 175), (164, 317), (165, 0), (166, 0), (167
139
Level 33
, 0), (168, 0), (169, 183), (170, 317), (171, 0), (172, 0), (173
, 0), (174, 0), (175, 171), (176, 337), (177, 0), (178, 0), (179
, 0), (180, 0), (181, 198), (182, 318), (183, 0), (184, 0), (185
, 0), (186, 0), (187, 241), (188, 283), (189, 0), (190, 0), (191
, 0), (192, 0), (193, 1348), (194, 272), (195, 0), (196, 0), (197
, 0), (198, 0), (199, 0), (200, 0), (201, 0), (202, 0), (203, 0)
, (204, 0), (205, 0), (206, 0), (207, 0), (208, 0), (209, 0), (2
10, 0), (211, 0), (212, 0), (213, 0), (214, 0), (215, 0), (216, 0
), (217, 0), (218, 0), (219, 0), (220, 0), (221, 0), (222, 0), (
223, 0), (224, 0), (225, 0), (226, 0), (227, 0), (228, 0), (229,
0), (230, 0), (231, 0), (232, 0), (233, 0), (234, 0), (235, 0), (
236, 0), (237, 0), (238, 0), (239, 0), (240, 0), (241, 0), (242,
0), (243, 0), (244, 0), (245, 0), (246, 0), (247, 0), (248, 0), (
249, 0), (250, 0), (251, 0), (252, 0), (253, 0), (254, 0), (255,
0)]
>>> sum([x for x in im.histogram() if x != 0][:-2])
17424
140
Level 33
gremlins
Final Link
http://www.pythonchallenge.com/pc/rock/gremlins.html
141
Appendix: Links
Links
Documentation
The Python Standard Library: (https://docs.python.org/3/library/index.html)
PEP 8: Style Guide for Python Code(https://www.python.org/dev/peps/pep0008/)
PIL: Python Imaging Library(fork that works with Python 3.x)
(http://pillow.readthedocs.io/)
Problems
Level 0:
problem: http://www.pythonchallenge.com/pc/def/0.html
unlock official solution:
http://www.pythonchallenge.com/pcc/def/map.html
Level 1:
problem: http://www.pythonchallenge.com/pc/def/map.html
unlock official solution: http://www.pythonchallenge.com/pcc/def/ocr.html
Level 2:
problem: http://www.pythonchallenge.com/pc/def/ocr.html
unlock official solution:
http://www.pythonchallenge.com/pcc/def/equality.html
Level 3:
problem: http://www.pythonchallenge.com/pc/def/equality.html
unlock official solution:
http://www.pythonchallenge.com/pcc/def/linkedlist.php
Level 4:
problem: http://www.pythonchallenge.com/pc/def/linkedlist.php
unlock official solution:
http://www.pythonchallenge.com/pcc/def/peak.html
Level 5:
problem: http://www.pythonchallenge.com/pc/def/peak.html
142
Appendix: Links
unlock official solution:
http://www.pythonchallenge.com/pcc/def/channel.html
Level 6:
problem: http://www.pythonchallenge.com/pc/def/channel.html
unlock official solution:
http://www.pythonchallenge.com/pcc/def/oxygen.html
Level 7:
problem: http://www.pythonchallenge.com/pc/def/oxygen.html
unlock official solution:
http://www.pythonchallenge.com/pcc/def/integrity.html
Level 8:
problem: http://www.pythonchallenge.com/pc/def/integrity.html
unlock official solution:
http://www.pythonchallenge.com/pcc/return/good.html
Level 9:
problem: http://www.pythonchallenge.com/pc/return/good.html
unlock official solution:
http://www.pythonchallenge.com/pcc/return/bull.html
username: huge
password: file
Level 10:
problem: http://www.pythonchallenge.com/pc/return/bull.html
unlock official solution:
http://www.pythonchallenge.com/pcc/return/5808.html
username: huge
password: file
Level 11:
problem: http://www.pythonchallenge.com/pc/return/5808.html
unlock official solution:
http://www.pythonchallenge.com/pcc/return/evil.html
username: huge
password: file
Level 12:
problem: http://www.pythonchallenge.com/pc/return/evil.html
unlock official solution:
http://www.pythonchallenge.com/pcc/return/disproportional.html
143
Appendix: Links
username: huge
password: file
Level 13:
problem: http://www.pythonchallenge.com/pc/return/disproportional.html
unlock official solution:
http://www.pythonchallenge.com/pcc/return/italy.html
username: huge
password: file
Level 14:
problem: http://www.pythonchallenge.com/pc/return/italy.html
unlock official solution:
http://www.pythonchallenge.com/pcc/return/uzi.html
username: huge
password: file
Level 15:
problem: http://www.pythonchallenge.com/pc/return/uzi.html
unlock official solution:
http://www.pythonchallenge.com/pcc/return/mozart.html
username: huge
password: file
Level 16:
problem: http://www.pythonchallenge.com/pc/return/mozart.html
unlock official solution:
http://www.pythonchallenge.com/pcc/return/romance.html
username: huge
password: file
Level 17:
problem: http://www.pythonchallenge.com/pc/return/romance.html
unlock official solution:
http://www.pythonchallenge.com/pcc/stuff/balloons.html
username: huge
password: file
Level 18:
problem: http://www.pythonchallenge.com/pc/stuff/balloons.html
unlock official solution:
http://www.pythonchallenge.com/pcc/hex/bin.html:butter:fly
144
Appendix: Links
username: huge
password: file
Level 19:
problem: http://www.pythonchallenge.com/pc/hex/bin.html
unlock official solution:
http://www.pythonchallenge.com/pcc/hex/idiot2.html
username: butter
password: fly
Level 20:
problem: http://www.pythonchallenge.com/pc/hex/idiot2.html
username: butter
password: fly
Level 21: NO LINK(inside the zip file from Level 20)
unlock official solution:
http://www.pythonchallenge.com/pcc/hex/copper.html
Level 22:
problem: http://www.pythonchallenge.com/pc/hex/copper.html
unlock official solution:
http://www.pythonchallenge.com/pcc/hex/bonus.html
username: butter
password: fly
Level 23:
problem: http://www.pythonchallenge.com/pc/hex/bonus.html
unlock official solution:
http://www.pythonchallenge.com/pcc/hex/ambiguity.html
username: butter
password: fly
Level 24:
problem: http://www.pythonchallenge.com/pc/hex/ambiguity.html
unlock official solution:
http://www.pythonchallenge.com/pcc/hex/lake.html
username: butter
password: fly
Level 25:
problem: http://www.pythonchallenge.com/pc/hex/lake.html
unlock official solution:
145
Appendix: Links
http://www.pythonchallenge.com/pcc/hex/decent.html
username: butter
password: fly
Level 26:
problem: http://www.pythonchallenge.com/pc/hex/decent.html
unlock official solution:
http://www.pythonchallenge.com/pcc/hex/speedboat.html
username: butter
password: fly
Level 27:
problem: http://www.pythonchallenge.com/pc/hex/speedboat.html
unlock official solution: http://www.pythonchallenge.com/pcc/ring/bell.html
username: butter
password: fly
Level 28:
problem: http://www.pythonchallenge.com/pc/ring/bell.html
unlock official solution:
http://www.pythonchallenge.com/pcc/ring/guido.html
username: repeat
password: switch
Level 29: -problem: http://www.pythonchallenge.com/pc/ring/guido.html
unlock official solution:
http://www.pythonchallenge.com/pcc/ring/yankeedoodle.html
username: repeat
password: switch
Level 30:
problem: http://www.pythonchallenge.com/pc/ring/yankeedoodle.html
unlock official solution:
http://www.pythonchallenge.com/pcc/ring/grandpa.html
username: repeat
password: switch
Level 31:
problem: http://www.pythonchallenge.com/pc/ring/grandpa.html
unlock official solution:
http://www.pythonchallenge.com/pcc/rock/arecibo.html
username: repeat
146
Appendix: Links
password: switch
username(after clicking the image): kohsamui
password(after clicking the image): thailand
Level 32:
problem: http://www.pythonchallenge.com/pc/rock/arecibo.html
unlock official solution:
http://www.pythonchallenge.com/pcc/rock/beer.html
username: kohsamui
password: thailand
Level 33:
problem: http://www.pythonchallenge.com/pc/rock/beer.html
unlock official solution:
http://www.pythonchallenge.com/pcc/rock/gremlins.html
username: kohsamui
password: thailand
147