My Python Challenge Solutions

In [1]:
# -- 0 --
# problem : http://www.pythonchallenge.com/pc/def/0.html
In [2]:
2**38
Out[2]:
274877906944
In [3]:
# -- 1 --
# problem : http://www.pythonchallenge.com/pc/def/map.html
# solution : http://www.pythonchallenge.com/pcc/def/ocr.html
In [4]:
input_string = "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."

def decode_string(string):
    def decode_char(char):
        return chr((((ord(char) + 2) - 97) % 26) + 97) if char.isalpha() else char
    return "".join(decode_char(char) for char in string)

decode_string(input_string)
Out[4]:
"i hope you didnt translate it by hand. thats what computers are for. doing it in by hand is inefficient and that's why this text is so long. using string.maketrans() is recommended. now apply on the url."
In [5]:
decode_string("map")
Out[5]:
'ocr'
In [6]:
# -- 2 --
# problem : http://www.pythonchallenge.com/pc/def/ocr.html
# solution : http://www.pythonchallenge.com/pcc/def/equality.html
In [7]:
import urllib.request
import re

def get_source(url):
    with urllib.request.urlopen(url) as response:
        html = response.read()
    return html

def print_source(url):
    print(get_source(url).decode())

html = get_source("http://www.pythonchallenge.com/pc/def/ocr.html")

# https://docs.python.org/3.6/howto/regex.html#greedy-versus-non-greedy
# https://docs.python.org/3.6/howto/regex.html#compilation-flags
input_string = re.findall(b"<!--(.*?)-->", html, flags = re.DOTALL)[-1].strip().decode()
"".join(char for char in input_string if char.isalpha())
Out[7]:
'equality'
In [8]:
# -- 3 --
# problem : http://www.pythonchallenge.com/pc/def/equality.html
# solution : http://www.pythonchallenge.com/pcc/def/linkedlist.php
In [9]:
html = get_source("http://www.pythonchallenge.com/pc/def/equality.html")
input_string = re.findall(b"<!--(.*?)-->", html, flags = re.DOTALL)[-1].strip().decode()
"".join(re.findall(r"[^A-Z]+[A-Z]{3}([a-z]{1})[A-Z]{3}[^A-Z]+", input_string))
Out[9]:
'linkedlist'
In [10]:
# -- 4 --
# problem : http://www.pythonchallenge.com/pc/def/linkedlist.php
# solution : http://www.pythonchallenge.com/pcc/def/peak.html
In [11]:
print_source("http://www.pythonchallenge.com/pc/def/linkedlist.php")
<html>
<head>
  <title>follow the chain</title>
  <link rel="stylesheet" type="text/css" href="../style.css">
</head>
<body>
<!-- urllib may help. DON'T TRY ALL NOTHINGS, since it will never 
end. 400 times is more than enough. -->
<center>
<a href="linkedlist.php?nothing=12345"><img src="chainsaw.jpg" border="0"/></a>
<br><br><font color="gold"></center>
Solutions to previous levels: <a href="http://wiki.pythonchallenge.com/"/>Python Challenge wiki</a>.
<br><br>
IRC: irc.freenode.net #pythonchallenge
</body>
</html>


In [12]:
get_source("http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing=12345")
Out[12]:
b'and the next nothing is 44827'
In [13]:
nothing = "12345"
while True:
    source = get_source("http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing={0}".format(nothing))
    try:
        nothing = re.findall(b"and the next nothing is ([0-9]+)", source)[0].decode()
    except:
        if source == b"Yes. Divide by two and keep going.":
            nothing = int(nothing)//2
        else:
            print(source)
            break
b'peak.html'
In [14]:
# -- 5 --
# problem : http://www.pythonchallenge.com/pc/def/peak.html
# solution : http://www.pythonchallenge.com/pcc/def/channel.html
In [15]:
print_source("http://www.pythonchallenge.com/pc/def/peak.html")
<html>
<head>
  <title>peak hell</title>
  <link rel="stylesheet" type="text/css" href="../style.css">
</head>
<body>
<center>
<img src="peakhell.jpg"/>
<br><font color="#c0c0ff">
pronounce it
<br>
<peakhell src="banner.p"/>
</body>
</html>

<!-- peak hell sounds familiar ? -->

In [16]:
import pickle

banner = pickle.loads(get_source("http://www.pythonchallenge.com/pc/def/banner.p"))
banner
Out[16]:
[[(' ', 95)],
 [(' ', 14), ('#', 5), (' ', 70), ('#', 5), (' ', 1)],
 [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)],
 [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)],
 [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)],
 [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)],
 [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)],
 [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)],
 [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)],
 [(' ', 6),
  ('#', 3),
  (' ', 6),
  ('#', 4),
  (' ', 3),
  ('#', 3),
  (' ', 9),
  ('#', 3),
  (' ', 7),
  ('#', 5),
  (' ', 3),
  ('#', 3),
  (' ', 4),
  ('#', 5),
  (' ', 3),
  ('#', 3),
  (' ', 10),
  ('#', 3),
  (' ', 7),
  ('#', 4),
  (' ', 1)],
 [(' ', 3),
  ('#', 3),
  (' ', 3),
  ('#', 2),
  (' ', 4),
  ('#', 4),
  (' ', 1),
  ('#', 7),
  (' ', 5),
  ('#', 2),
  (' ', 2),
  ('#', 3),
  (' ', 6),
  ('#', 4),
  (' ', 1),
  ('#', 7),
  (' ', 3),
  ('#', 4),
  (' ', 1),
  ('#', 7),
  (' ', 5),
  ('#', 3),
  (' ', 2),
  ('#', 3),
  (' ', 5),
  ('#', 4),
  (' ', 1)],
 [(' ', 2),
  ('#', 3),
  (' ', 5),
  ('#', 3),
  (' ', 2),
  ('#', 5),
  (' ', 4),
  ('#', 4),
  (' ', 3),
  ('#', 3),
  (' ', 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)]]
In [17]:
def row_string(list_of_tuples):
    return "".join(char*num for char, num in list_of_tuples)
print(*map(row_string, banner), sep = "\n")
              #####                                                                      ##### 
               ####                                                                       #### 
               ####                                                                       #### 
               ####                                                                       #### 
               ####                                                                       #### 
               ####                                                                       #### 
               ####                                                                       #### 
               ####                                                                       #### 
      ###      ####   ###         ###       #####   ###    #####   ###          ###       #### 
   ###   ##    #### #######     ##  ###      #### #######   #### #######     ###  ###     #### 
  ###     ###  #####    ####   ###   ####    #####    ####  #####    ####   ###     ###   #### 
 ###           ####     ####   ###    ###    ####     ####  ####     ####  ###      ####  #### 
 ###           ####     ####          ###    ####     ####  ####     ####  ###       ###  #### 
####           ####     ####     ##   ###    ####     ####  ####     #### ####       ###  #### 
####           ####     ####   ##########    ####     ####  ####     #### ##############  #### 
####           ####     ####  ###    ####    ####     ####  ####     #### ####            #### 
####           ####     #### ####     ###    ####     ####  ####     #### ####            #### 
 ###           ####     #### ####     ###    ####     ####  ####     ####  ###            #### 
  ###      ##  ####     ####  ###    ####    ####     ####  ####     ####   ###      ##   #### 
   ###    ##   ####     ####   ###########   ####     ####  ####     ####    ###    ##    #### 
      ###     ######    #####    ##    #### ######    ###########    #####      ###      ######
                                                                                               
In [18]:
# -- 6 --
# problem : http://www.pythonchallenge.com/pc/def/channel.html
# solution : http://www.pythonchallenge.com/pcc/def/oxygen.html
In [19]:
print_source("http://www.pythonchallenge.com/pc/def/channel.html")
<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/>
<!-- 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
-->

<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
    <input type="hidden" name="cmd" value="_xclick">
    <input type="hidden" name="business" value="[email protected]">
    <input type="hidden" name="item_name" value="Python Challenge donations">
    <input type="hidden" name="no_note" value="1">
    <input type="hidden" name="currency_code" value="USD">
    <input type="hidden" name="tax" value="0">
    <input type="hidden" name="bn" value="PP-DonationsBF">
    <input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-but04.gif" border="0" name="submit" alt="Make payments with PayPal - it's fast, free and secure!">
    <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1">
</form>

</body>
</html>

In [20]:
import shutil

# Download the file from `url` and save it locally under `file_name`:
def download_file(url,file_name):
    with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file:
        shutil.copyfileobj(response, out_file)

download_file("http://www.pythonchallenge.com/pc/def/channel.zip", "channel.zip")
In [21]:
from zipfile import ZipFile

def read_archive_member(archive_filename, member_filename):
    with ZipFile(archive_filename) as archive:
        with archive.open(member_filename) as member:
            return member.read().decode()

print(read_archive_member(archive_filename = "channel.zip", member_filename = "readme.txt"))
welcome to my zipped list.

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

In [22]:
read_archive_member(archive_filename = "channel.zip", member_filename = "90052.txt")
Out[22]:
'Next nothing is 94191'
In [23]:
nothing = "90052"
while True:
    try:
        contents = read_archive_member(archive_filename = "channel.zip", member_filename = "{0}.txt".format(nothing))
        nothing = re.findall("Next nothing is ([0-9]+)", contents)[0]
    except:
        print(contents)
        break
Collect the comments.
In [24]:
# https://docs.python.org/3/library/zipfile.html#zipfile.ZipFile.comment
with ZipFile("channel.zip") as archive:
    print(archive.comment)
b''
In [25]:
# https://docs.python.org/3/library/zipfile.html#zipfile.ZipInfo.comment
archive = "channel.zip"
nothing = "90052"
comments = []
while True:
    try:
        member = "{0}.txt".format(nothing)
        contents = read_archive_member(archive, member)
        comments.append(ZipFile(archive).getinfo(member).comment.decode())
        nothing = re.findall("Next nothing is ([0-9]+)", contents)[0]
    except:
        print(*comments, sep = "")
        break
****************************************************************
****************************************************************
**                                                            **
**   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      **
**                                                            **
****************************************************************
 **************************************************************

In [26]:
print_source("http://www.pythonchallenge.com/pc/def/hockey.html")
it's in the air. look at the letters. 

In [27]:
print_source("http://www.pythonchallenge.com/pc/def/oxygen.html")
<html>
<head>
  <title>smarty</title>
  <link rel="stylesheet" type="text/css" href="../style.css">
</head>
<body>
	<br><br>
	<center>
	<img src="oxygen.png"/>
</body>
</html>

In [28]:
# -- 7 --
# problem : http://www.pythonchallenge.com/pc/def/oxygen.html
# solution : http://www.pythonchallenge.com/pcc/def/integrity.html
In [29]:
download_file("http://www.pythonchallenge.com/pc/def/oxygen.png","oxygen.png")
In [30]:
from PIL import Image
im = Image.open("oxygen.png")
print(im.size, im.mode)
(629, 95) RGBA
In [31]:
chars = []
for x in range(0, 630, 7):
    (r, g, b, a) = im.getpixel((x, 43))
    if r == g == b:
        chars.append(chr(r))
print(*chars, sep = "")
smart guy, you made it. the next level is [105, 110, 116, 101, 103, 114, 105, 116, 121]
In [32]:
print(*map(chr, [105, 110, 116, 101, 103, 114, 105, 116, 121]), sep = "")
integrity
In [33]:
# -- 8 --
# problem : http://www.pythonchallenge.com/pc/def/integrity.html
# solution : http://www.pythonchallenge.com/pcc/return/good.html:huge:file
In [34]:
print_source("http://www.pythonchallenge.com/pc/def/integrity.html")
<html>
<head>
  <title>working hard?</title>
  <link rel="stylesheet" type="text/css" href="../style.css">
</head>
<body>
	<br><br>
	<center>
	<img src="integrity.jpg" width="640" height="480" border="0" usemap="#notinsect"/>
	<map name="notinsect">
	<area shape="poly" 
		coords="179,284,214,311,255,320,281,226,319,224,363,309,339,222,371,225,411,229,404,242,415,252,428,233,428,214,394,207,383,205,390,195,423,192,439,193,442,209,440,215,450,221,457,226,469,202,475,187,494,188,494,169,498,147,491,121,477,136,481,96,471,94,458,98,444,91,420,87,405,92,391,88,376,82,350,79,330,82,314,85,305,90,299,96,290,103,276,110,262,114,225,123,212,125,185,133,138,144,118,160,97,168,87,176,110,180,145,176,153,176,150,182,137,190,126,194,121,198,126,203,151,205,160,195,168,217,169,234,170,260,174,282" 
		href="../return/good.html" />
	</map>
	<br><br>
	<font color="#303030" size="+2">Where is the missing link?</font>
</body>
</html>

<!--
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'
-->

In [35]:
# The server reports that it is from inflate.
# Opposite of "inflate" -- "compress"
# un -- (u)ser(n)ame
# pw -- (p)ass(w)ord

import codecs

source = get_source("http://www.pythonchallenge.com/pc/def/integrity.html")
# http://stackoverflow.com/a/37059682
# http://stackoverflow.com/a/23151714
comment = codecs.escape_decode(re.findall(b"<!--(.*?)-->", source, flags = re.DOTALL)[0])[0]
un = re.findall(b"\nun: '(.*?)'", comment)[0]
pw = re.findall(b"\npw: '(.*?)'", comment)[0]
In [36]:
# https://en.wikipedia.org/wiki/List_of_file_signatures
# bz2 -- Compressed file using Bzip2 algorithm -- BZh
import bz2
bz2.decompress(un)
Out[36]:
b'huge'
In [37]:
bz2.decompress(pw)
Out[37]:
b'file'
In [ ]:
# -- 9 --
# problem : [url-- http://www.pythonchallenge.com/pc/return/good.html] [username-- huge] [password-- file]
# solution :