{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# The Python Challenge\n", "\n", "\n", "## 0. warming up\n", "\n", "\n", "![TV with 2^38 text displayed](images/0.jpg)\n", "*Hint: try to change the URL address.*" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "2 ** 38 # or pow(2, 38)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next URL: " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. What about making trans?\n", "\n", "\n", "![A notepad page with K->M, O->Q, E->Q text](images/1.jpg \"everybody thinks twice before \n", "solving this.\")\n", "*everybody thinks twice before solving this.*\n", "\n", "> 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.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "text = (\"g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amknsrcpq ypc dmp. \"\n", " \"bmgle gr gl zw fylb gq glcddgagclr ylb rfyr'q ufw rfgq rcvr gq qm jmle. \"\n", " \"sqgle qrpgle.kyicrpylq() gq pcamkkclbcb. lmu ynnjw ml rfc spj.\")\n", "\n", "trans_table = str.maketrans('abcdefghijklmnopqrstuvwxyz',\n", " 'cdefghijklmnopqrstuvwxyzab')\n", "\n", "text.translate(trans_table)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "'map'.translate(trans_table)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. ocr\n", "\n", "\n", "![An open book with small, unreadable text](images/2.jpg)\n", "*recognize the characters. maybe they are in the book, \n", "but MAYBE they are in the page source.*\n", "\n", "> To see the solutions to the previous level, replace pc with pcc, i.e. go to: http://www.pythonchallenge.com/pcc/def/ocr.html\n", "\n", "Hints:\n", "\n", "find rare characters in the mess below:\n", "\n", "```\n", "%%$@_$^__#)^)&!_+]!*@&^}@[@%]()%+$&[(_@%+%$*^@$^!+]!&_#)_*}{}}!}_]$[%}@[{_@#_^{*\n", "@##&{#&{&)*%(]{{([*}@[@&]+!!*{)!}{%+{))])[!^})+)$]#{*+^((@^@}$[**$&^{$!@#$%)!@(&\n", "+^!{%_$&@^!}$_${)$_#)!({@!)(^}!*^&!$%_&&}&_#&@{)]{+)%*{&*%*&@%$+]!*__(#!*){%&@++\n", "...\n", "```\n", "\n", "[full text](resources/2-source.txt)\n", " \n", "Useful links:\n", "- \n", "- " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from collections import Counter\n", "\n", "with open('resources/2-source.txt') as f:\n", " text = ''.join(f.read().splitlines())\n", "\n", "c = Counter(text)\n", "c.most_common()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. re\n", "\n", "\n", "![3 big candles, then one small floating candle, and then 3 big candles again in row](images/3.jpg)\n", "*One small letter, surrounded by __EXACTLY__ three big bodyguards on each of its sides.*\n", "\n", "Hints:\n", "\n", " kAewtloYgcFQaJNhHVGxXDiQmzjfcpYbzxlWrVcqsmUbCunkfxZWDZjUZMiGqhRRiUvGmYmvnJIHEmbT\n", " MUKLECKdCthezSYBpIElRnZugFAxDRtQPpyeCBgBfaRVvvguRXLvkAdLOeCKxsDUvBBCwdpMMWmuELeG\n", " ENihrpCLhujoBqPRDPvfzcwadMMMbkmkzCCzoTPfbRlzBqMblmxTxNniNoCufprWXxgHZpldkoLCrHJq\n", " ...\n", "\n", "[full text](resources/3-source.txt)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import re\n", "\n", "with open('resources/3-source.txt') as f:\n", " text = ''.join(f.read().splitlines())\n", " \n", "letter_with_3_bodyguards_re = re.compile(r'[a-z][A-Z]{3}([a-z])[A-Z]{3}[a-z]')\n", "\n", "letter_with_3_bodyguards_re.findall(text)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next URL: " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4. follow the chain\n", "http://www.pythonchallenge.com/pc/def/linkedlist.php\n", "\n", "[![two man logging crosscut tree saw wooden toy](images/4.jpg)](http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing=12345)\n", "\n", "> Solutions to previous levels: [Python Challenge wiki](http://wiki.pythonchallenge.com/).\n", "\n", "Hints:\n", "\n", "> urllib may help. DON'T TRY ALL NOTHINGS, since it will never \n", "> end. 400 times is more than enough." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import re\n", "from urllib.request import urlopen\n", "\n", "url_template = 'http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing={}'\n", "nothing = '12345'\n", "nothing_re = re.compile(r'next nothing is (\\d+)')\n", "\n", "for i in range(1, 401):\n", " with urlopen(url_template.format(nothing)) as response:\n", " html = response.read().decode('utf-8')\n", " # print(\"{:03}. {}\".format(i, html))\n", " \n", " print('.', sep='', end='')\n", "\n", " match = nothing_re.search(html)\n", " if match:\n", " nothing = match.group(1)\n", " else:\n", " if 'divide by two' in html.lower():\n", " nothing = int(nothing) / 2\n", " else:\n", " print(html)\n", " break" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5. peak hell\n", "http://www.pythonchallenge.com/pc/def/peak.html\n", "\n", "![green round mountain](images/5.jpg)\n", "*pronounce it*\n", "\n", "Hints:\n", "\n", " \n", "\n", " \n", " \n", "[banner.p](resources/5-banner.p)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import pickle\n", "\n", "def ascii_printer(data):\n", " for row in data:\n", " for char, num in row:\n", " print(char * num, sep='', end='')\n", " print()\n", "\n", "with open('resources/5-banner.p', 'rb') as f:\n", " data = pickle.load(f)\n", " \n", "ascii_printer(data)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6. now there are pairs\n", "\n", "\n", "![black pants with open zipper](images/6.jpg)\n", "\n", "Hints:\n", "\n", " \n", " \n", "" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import re\n", "import zipfile\n", "\n", "nothing = '90052'\n", "nothing_re = re.compile(r'next nothing is (\\d+)')\n", "comments = []\n", "\n", "with zipfile.ZipFile('resources/6-channel.zip', 'r') as zf:\n", " for _ in range(len(zf.namelist())):\n", " filename = '{}.txt'.format(nothing)\n", " text = zf.read(filename).decode('utf-8')\n", " info = zf.getinfo(filename)\n", " \n", " comments.append(info.comment.decode('ascii'))\n", "\n", " match = nothing_re.search(text.lower())\n", " if match:\n", " nothing = match.group(1)\n", " else:\n", " print(text)\n", " break\n", "\n", "print()\n", "print(''.join(comments))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next URL: http://www.pythonchallenge.com/pc/def/hockey.html" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 7. smarty\n", "\n", "\n", "![river shore. grayscale line crossing the image](images/7.png)\n", "\n", "Research:\n", "![enlarged grayscale line](images/7-grayscale-line-enlarged.png)\n", "*Enlarged grayscale line of the original image*\n", "\n", "Grayscale line consist of 7x9 px blocks (except the first one, which is 5x9, and last one, which is 8x9) of the same color. Let's collect shades of gray of each block.\n", "\n", "Useful links:\n", "- https://stackoverflow.com/questions/138250/how-can-i-read-the-rgb-value-of-a-given-pixel-in-python" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from PIL import Image\n", "\n", "im = Image.open('images/7.png')\n", "px = im.load()\n", "\n", "# center of the 2nd block\n", "x = 8\n", "y = 47\n", "block_width = 7\n", "\n", "color_values = []\n", "# extract shade of gray of the center of the 1st block\n", "color_values.append(px[2, 47][0])\n", "\n", "# extract shades of other blocks\n", "while x < 608:\n", " color_values.append(px[x, y][0])\n", " x += block_width\n", "\n", "print(''.join(chr(v) for v in color_values))\n", "\n", "print(''.join(chr(v) for v in [105, 110, 116, 101, 103, 114, 105, 116, 121]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 8. working hard?\n", "http://www.pythonchallenge.com/pc/def/integrity.html\n", "\n", "[![A fly on a flower](images/8.jpg)](http://www.pythonchallenge.com/pc/return/good.html)\n", "*Where is the missing link?*\n", "\n", "Hints:\n", "\n", " un: 'BZh91AY&SYA\\xaf\\x82\\r\\x00\\x00\\x01\\x01\\x80\\x02\\xc0\\x02\\x00 \\x00!\\x9ah3M\\x07<]\\xc9\\x14\\xe1BA\\x06\\xbe\\x084'\n", " pw: 'BZh91AY&SY\\x94$|\\x0e\\x00\\x00\\x00\\x81\\x00\\x03$ \\x00!\\x9ah3M\\x13<]\\xc9\\x14\\xe1BBP\\x91\\xf08'\n", "\n", "Research:\n", "- https://www.google.ru/search?q=BZh91AY" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import bz2\n", "\n", "un = b'BZh91AY&SYA\\xaf\\x82\\r\\x00\\x00\\x01\\x01\\x80\\x02\\xc0\\x02\\x00 \\x00!\\x9ah3M\\x07<]\\xc9\\x14\\xe1BA\\x06\\xbe\\x084'\n", "pw = b'BZh91AY&SY\\x94$|\\x0e\\x00\\x00\\x00\\x81\\x00\\x03$ \\x00!\\x9ah3M\\x13<]\\xc9\\x14\\xe1BBP\\x91\\xf08'\n", "\n", "print(bz2.decompress(un), bz2.decompress(pw))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 9. connect the dots\n", "http://www.pythonchallenge.com/pc/return/good.html\n", "\n", "![branches of a dry tree. small black points follow its curves](images/9.jpg)\n", "\n", "> To see the solutions to the previous level, replace pc with pcc and add :un:pw\n", "> i.e. go to: http://www.pythonchallenge.com/pcc/return/good.html:huge:file\n", "> \n", "> Join us at the IRC: irc.freenode.net #pythonchallenge\n", "\n", "*Hints:*\n", "\n", "first+second=?\n", "\n", "first: \n", "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, \n", "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, \n", "... \n", "[first.txt](resources/9-first.txt)\n", "\n", "second: \n", "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, \n", "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, \n", "... \n", "[second.txt](resources/9-second.txt)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "\n", "with open('resources/9-first.txt') as f1, \\\n", " open('resources/9-second.txt') as f2:\n", " first = f1.read()\n", " second = f2.read()\n", "\n", "first = [int(s.strip()) for s in first.split(',')]\n", "second = [int(s.strip()) for s in second.split(',')]\n", "\n", "plt.plot(first[::2], first[1::2], linewidth=4)\n", "plt.plot(second[::2], second[1::2], linewidth=4)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 10. what are you looking at?\n", "http://www.pythonchallenge.com/pc/return/bull.html\n", "\n", "[![A cow looking at you](images/10.jpg)](http://www.pythonchallenge.com/pc/return/sequence.txt)\n", "*len(a[30]) = ?*\n", "\n", "[sequence.txt](http://www.pythonchallenge.com/pc/return/sequence.txt):\n", "\n", " a = [1, 11, 21, 1211, 111221,\n", " \n", "Research:\n", "- [google 1, 11, 21, 1211, 111221](https://www.google.com/search?q=1%2C+11%2C+21%2C+1211%2C+111221)\n", "- https://en.wikipedia.org/wiki/Look-and-say_sequence" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def look_and_say(number):\n", " next_number = []\n", " \n", " while number:\n", " digit = number[0]\n", " number_left = number.lstrip(digit)\n", " \n", " next_number.append('{count}{digit}'.format(\n", " digit=digit,\n", " count=len(number) - len(number_left)\n", " ))\n", " \n", " number = number_left\n", " \n", " return ''.join(next_number)\n", "\n", "number = '1'\n", "for _ in range(30):\n", " number = look_and_say(number)\n", "\n", "print(len(number))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 11. odd even\n", "http://www.pythonchallenge.com/pc/return/5808.html\n", "\n", "![blurry figures of people](images/11.jpg)\n", "\n", "Research:\n", "![top left corner magnified](images/11-top-left-corner-magnified.png)\n", "*Magnified top left corner of the original image*\n", "\n", "There're 2 kinds of pixels: black and green. Let's try to extract black ones.\n", "\n", "Useful links:\n", "- https://stackoverflow.com/questions/26649716/how-to-show-pil-image-in-ipython-notebook" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from IPython.display import display\n", "# from matplotlib.pyplot import imshow\n", "import numpy as np\n", "from PIL import Image\n", "\n", "im = Image.open('images/11.jpg')\n", "ima = np.array(im)\n", "\n", "# im1a = np.array([[[0,0,0] for x in range(ima.shape[1] // 2)]\n", "# for y in range(ima.shape[0])],\n", "# dtype=np.uint8)\n", "im1a = np.zeros((ima.shape[0], ima.shape[1] // 2, 3), dtype=np.uint8)\n", "\n", "for i, row in enumerate(ima):\n", " # if row is even, copy every second pixel, starting from 0\n", " if i % 2 == 0:\n", " im1a[i] = ima[i, ::2]\n", " # otherwise, copy odd ones\n", " else:\n", " im1a[i] = ima[i, 1::2]\n", "\n", "# Image.fromarray(im1a).show()\n", "# imshow(im1a)\n", "display(Image.fromarray(im1a))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 12. dealing evil\n", "http://www.pythonchallenge.com/pc/return/evil.html\n", "\n", "![A table with playing cards](images/12.jpg)\n", "\n", "Hints:\n", "- [evil2.jpg](http://www.pythonchallenge.com/pc/return/evil2.jpg),\n", "- [evil3.jpg](http://www.pythonchallenge.com/pc/return/evil3.jpg),\n", "- [evil4.jpg](http://www.pythonchallenge.com/pc/return/evil4.jpg) (not an image - contains text \"Bert is evil! go back!\")\n", "\n", "[evil2.gfx](resources/12-evil2.gfx)\n", "\n", "Research:\n", "\n", "Let's assume [gfx stands for graphics](https://en.wiktionary.org/wiki/gfx).\n", "\n", "Let's get [signatures](https://en.wikipedia.org/wiki/List_of_file_signatures) of the popular image formats:\n", "\n", " jpg: FF D8 FF\n", " png: 89 50 4E 47\n", " gif: 47 49 46 38\n", " \n", "Start of the evil2.gfx:\n", "\n", " $ xxd -g 1 -l 48 -u resources/12-evil2.gfx\n", " \n", " 00000000: FF 89 47 89 FF D8 50 49 50 D8 FF 4E 46 4E FF E0 ..G...PIP..NFN..\n", " 00000010: 47 38 47 E0 00 0D 37 0D 00 10 0A 61 0A 10 4A 1A G8G...7....a..J.\n", " 00000020: 40 1A 4A 46 0A 01 0A 46 49 00 F0 00 49 46 00 00 @.JF...FI...IF..\n", " \n", "`FF 89 47 89 FF` is the first bytes of jpg, png, gif, png, jpg signatures.\n", "May be there're 5 files mixed? If we stack 5 bytes block one after another,\n", "then columns of this tables are the content of the correspondent file.\n", "\n", "\n", "Useful links:\n", "- https://stackoverflow.com/questions/1765311/how-to-view-files-in-binary-in-the-terminal\n", "- https://en.wikipedia.org/wiki/List_of_file_signatures\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import io\n", "from IPython.display import display\n", "import numpy as np\n", "from PIL import Image, ImageFile\n", "\n", "# Looks like 4th file is broken\n", "ImageFile.LOAD_TRUNCATED_IMAGES = True\n", "\n", "def image_from_array(arr):\n", " return Image.open(io.BytesIO(np.ascontiguousarray(arr)))\n", "\n", "gfx_a = np.fromfile('resources/12-evil2.gfx', dtype=np.uint8)\n", "# Reshape bytes to 5 colums table\n", "gfx_a = gfx_a.reshape(gfx_a.size // 5, 5)\n", "\n", "# Read columns top to bottom\n", "display(image_from_array(gfx_a[:, 0]))\n", "display(image_from_array(gfx_a[:, 1]))\n", "display(image_from_array(gfx_a[:, 2]))\n", "display(image_from_array(gfx_a[:, 3]))\n", "display(image_from_array(gfx_a[:, 4]))\n", "\n", "# gfx_a[:, 0].tofile('12-1.jpg')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 13. call him\n", "http://www.pythonchallenge.com/pc/return/disproportional.html\n", "\n", "[![A telephone keypad](images/13.jpg)](http://www.pythonchallenge.com/pc/phonebook.php)\n", "*phone that evil*\n", "\n", "Hints:\n", "- http://www.pythonchallenge.com/pc/phonebook.php\n", "\n", "Research:\n", "\n", "If we request phonebook.php, we get the following:\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " faultCode\n", " \n", " 105\n", " \n", " \n", " \n", " faultString\n", " \n", " XML error: Invalid document end at line 1, column 1\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "Quick search shows it's [XML-RPC](http://xmlrpc.scripting.com/spec.html) error response.\n", "Let's make a proper request. After some tries returning 'He is not the evil', we remember last puzzle saying 'Bert is evil!'\n", "\n", "[request.xml](resources/13-request.xml)\n", "\n", "Useful links:\n", "- [HTTPie – command line HTTP client](https://httpie.org/)\n", "- [Insomnia REST Client](https://insomnia.rest/)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from urllib.request import Request, urlopen\n", "\n", "with open('resources/13-request.xml') as f:\n", " r = Request(\n", " 'http://www.pythonchallenge.com/pc/phonebook.php',\n", " headers={\n", " 'Content-Type': 'text/xml; charset=utf-8'\n", " },\n", " data=f.read().encode('utf-8')\n", " )\n", "\n", "print(urlopen(r).read().decode('utf-8'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 14. walk around\n", "http://www.pythonchallenge.com/pc/return/italy.html\n", "\n", "![A bun](images/14.jpg)\n", "\n", "Hints:\n", "\n", "> remember: 100*100 = (100+99+99+98) + (..." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.1" } }, "nbformat": 4, "nbformat_minor": 2 }