Archive for the ‘Python’ Category

Python Challenge level 18: “can you tell the difference?”

Level 18 is imaginative again.

Hint 1: it is more obvious that what you might think.

Fact 1: the main difference between images is brightness, we’ll go to brightness.html which is an almost twin page except for a new hint.

Hint 2: maybe consider deltas.gz.

After retrieving deltas.gz, we can go on with the script:

import gzip,difflib
deltas=gzip.GzipFile('deltas.gz', 'rb').read()
deltas=deltas.splitlines()
left,right,png=[],[],['','','']
for row in deltas:
    left.append(row[:53])
    right.append(row[56:])
diff = list(difflib.ndiff(left,right))

for row in diff:
    bytes = [chr(int(byte,16)) for byte in row[2:].split()]
    if row[0]=='-': png[0]+=''.join(bytes)
    elif row[0]=='+': png[1]+=''.join(bytes)
    elif row[0]==' ': png[2]+=''.join(bytes)

for i in range(3):
    open('18_%d.png' %i,'wb').write(png[i])

The images created show the following texts:

18_0.png: fly
18_1.png: butter
18_2.png: ../hex/bin.html

That’s that. As allways, once you figure out the module you should be using makes the solution pretty straight forward. Level 19 is next.

Read the rest of this entry »

Python Challenge level 17: “eat?”

Level 17 is cookie related, so urllib usage is needed once again.

Hint 1: cookies in the photo. Unambiguous!
Hint 2: there’s a thumbnail of the image from level 4

So, we’ll have to investiagate the http headers. Interestingly, we find out something in level 4.

Fact 1:info=you+should+have+followed+busynothing…;” is a cookie set by level 4.
Fact 2: busynothing is another linkedlist, and has a chinging cookie!
Fact 3: once obtained every piece, the info seems to be a quote_plus string from a BZ2 chunk of data

The code for this part of the riddle would be:

import urllib,re,bz2
url='http://www.pythonchallenge.com/pc/def/linkedlist.php?busynothing='
seed="12345"
info=''
while True:
    req=urllib.urlopen(url+seed)
    text=req.read()
    seed=''.join(re.findall(r"busynothing is (\d+)",text))
    cookies=req.info().getheaders('Set-Cookie')[0]
    byte=cookies.split(';')[0].split('=')[1]
    info+=byte
    try :
        int(seed)
        print "   Info:",byte,"t   Next:",seed
    except :
        print "   Info:",byte,"t   Last:",text
        break
print "info:",bz2.decompress(urllib.unquote_plus(info))

is it the 26th already? call his father and inform him that “the flowers are on their way”. he’ll understand.

This one is intricate. Lets use level 13′s phonebook to find Mozart’s father’s phone. His name was Leopold by the way:

violin

From there to here, and stuck again. The only hint now is the page title: “it’s me. what do you want?”
Now it’s time to give him the message. After some trial and error and no RPC errors seen, setting a cookie with the message will show itself as the way to go.

from urllib2 import Request,urlopen
from urllib import quote_plus
info='the flowers are on their way'
url='http://www.pythonchallenge.com/pc/stuff/violin.php'
req = Request(url, headers={'Cookie': 'info=' + quote_plus(info)})
print urlopen(req).read()

oh well, don’t you dare to forget the balloons

Balloons! Finally Level 18.

Read the rest of this entry »

Python Challenge level 16: “let me get this straight”

In level 16 the title says everything.

Hint 1: there are 5 pink pixels in each row
Fact 1: pink is color 195 in the image’s color index (says The Gimp).

import urllib, Image,cStringIO
def straighten(line): # five equal consecutive pink pixels are the clue
    idx=0
    while line[idx]!=195:
        idx+=1
    return line[idx:]+line[:idx]

url = 'http://huge:file@www.pythonchallenge.com/pc/return/mozart.gif'
im = Image.open(cStringIO.StringIO(urllib.urlopen(url).read()))
for y in range(im.size[1]):
    line=[im.getpixel((x, y)) for x in range(im.size[0])]
    line=straighten(line)
    [im.putpixel((x, y),line[x]) for x in range(len(line))]
im.save('16.gif')

We don’t really need “Fact 1” to solve this problem, but it simplifies the code a bit. Instead of looking for pink pixels my first version looked for five equal pixels, but the result was slightly distorted in the lines where the level number is drawn.

The resulting image shows the word “romance”, and that’s where Level 17 awaits. I must say number 17 looks good. The most promising I’ve seen until now, and I’ve loved almost every single one of them. We’ll see if it can be as easily solved as this one.

Read the rest of this entry »

Python Challenge level 15: “whom?”

Level 15. I didn’t like this one. Not a bit. I think it’s the only level not as well designed as the rest. At least up untill now. Either that or my mindset doesn’t like some types of riddle as much as the rest. We are given a date in a callendar and a couple of hints.

Hint 1: he ain’t the youngest, he is the second
Hint 2: todo: buy flowers for tomorrow
Hint 3: whoever it is has something to do with a leap year, between 1006 and 1996 in which Jan 26 was Monday

I could easily generate some dates with the appropiate constraints, but the problem didn’t seem narrower. I had to read the forums for ideas. At first I was tricked by the image because it seemed to have just one digit missing in the year. I believe this was intentional. The hint about the flowers could mean many things: a death, a marriage, a birth…
So to the forums it is. These are excellent by the way, although by the absence of recent posts I think I’m tha last guy on Earth playing the game. Everybody seems to have finished long ago. The threads are classified by challenge level, no spoilers are allowed and there’s a lot of valuable hints. After reading the forums, I got some things straight.

Fact 1: the year is between 1006 and 1996. This narrows the thing a lot.
Fact 2: birth day is Jan 27. Better go to Wikipedia to get a list of events that happened that day.

#!/usr/bin/env python
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

1176-01-26
1356-01-26
1576-01-26
1756-01-26
1976-01-26

The second youngest would have been born on 1756. Since it’s the next day, 1756-01-27. After going to Wikipedia there is finally an answer, Mozart. And that’s that. Im glad it’s over. Now to Level 16.

Read the rest of this entry »

Python Challenge level 14: “walk around”

Level 14 is really short once again.

Hint 1: image is a spiral. It’s direction could be meaningful
Hint 2: remember: 100*100 = (100+99+99+98) + …. (3+2+2+1)+1
Fact 1: wire.jpg is 1×10000 pixels = 100*100

I especially liked this level because it was straight forward. You didn’t have to imagine obscure meanings hidden in the hints. The wire.jpg is so streched that it resembles a barcode, so you can automatically know that there is something encoded somehow. Also the 100*100 sequence hint, and the 100*100 pixels couldn’t be clearer. I think it is the first level I solved in under 5 minutes since the easy ones at the beginning of the game.

#!/usr/bin/env python
import Image
im = Image.open("wire.png")
new = Image.new(im.mode,[100,100])
doubled_steps=200
directions=[(1,0), (0,1), (-1,0), (0,-1)] # vectors in [x,y] format
x,y,p=-1,0,0
while doubled_steps//2 > 0:
    for v in directions: # we will be taking steps in 4 directions
        steps=doubled_steps//2
        for s in range(steps):
            x,y=x+v[0],y+v[1]
            new.putpixel((x,y),im.getpixel((p,0)))
            p+=1
        doubled_steps-=1
new.save('14.jpg')

It’s a cat. We’ll learn its name in cat.html as well as the place to go if we’re looking for Level 15.

Read the rest of this entry »

Python Challenge level 13: “call him”

For level 13 you need a tip from the last challenge.

Hint 1: phone that evil
Hint 2: link to phonebook.php, which returns an XMLRPC error
Fact 1: we know from the previous level that “Bert is evil”

#!/usr/bin/env python
import xmlrpclib
server = xmlrpclib.Server('http://www.pythonchallenge.com
/pc/phonebook.php')
## we'll need to discover Server API
# print server.system.listMethods()
print server.phone('Bert')

555-ITALY

This one was shorter than expected. Now to Level 14.

Read the rest of this entry »

Python Challenge level 12: “dealing evil”

Level 12 requires some hex-observation.

Hint 1: image evil1.jpg with a shuffled deck and five piles

The name evil1 seems suspicious, so maybe we can find something else poking around.

Fact 1: there are more evil?.jpg and an evil2.gfx

Fact 2: when inspected in an hex editor the gfx file seems to have several images interleaved. You don’t have to be a genius to recognize a JPEG header, but the GIF87a is much more obvious. Not everybody is used to reading binary files, but simply by watching you can get the idea that each file is shuffled every 5 bytes. So the task will be deshuffling evil2.gfx into 5 piles

Fact 3: when trying to retrieve file evil4.jpg a text appears “http://www.pythonchallenge.com/pc/return/evil4.jpg” and the source code is “Bert is evil! go back!”. This is not useful right now, but keep it in mind. It may come in handy in the future.

That’s a lot of text for one post ;) At least the task is clear. Two lines of code should suffice:

#!/usr/bin/env python
info=open("evil2.gfx").read()
[open("12_f%d.dat" %i, "w").write(info[i::5]) for i in range(5)]

My image viewer doesn’t really care for the file extension, so “.bin” suits me fine. Anyway you could allways use the file command in case yours cares.

Once we view the images, we get the link for Level 13.

Read the rest of this entry »

Python Challenge level 11: “odd even”

Level 11 requires playing with images once again.

Fact 1: the image cave.jpg seems to have half ot its pixels blanked
We’ll assume odd and even pixels belong to different images. This snippet will put me out of my misery and let me know ;)

import Image
src = Image.open("cave.jpg")
w,h = src.size[0], src.size[1]
print "Image info:",src.format, src.size, src.mode
new = Image.new(src.mode,(w//2, h))

for i in range(w*h):
    y, x = divmod(i, w)
    p = src.getpixel((x,y))
    if i%2: #even==info, odd==photo
        new.putpixel((x/2,y/2+h//2),p)
    else:
        new.putpixel((x/2,y/2),p)
new.save('11.jpg')

Now it’s readable. “evil“. Next is Level 12.

Read the rest of this entry »

Python Challenge level 10: “where are you looking at”

Level 10 doesn’t have anything new.

Hint 1: len(a[30]) = ?
Hint 2: a = [1, 11, 21, 1211, 111221,
Fact 1: 'a' is the 'look and say sequence'.
Im normally pretty good finding numeric patterns, but I must confess that I had to look up this one. I suppose I don't have the right mindset to mix numbers and words.

a=['1']
for i in range(30):
    elem=a[-1]+’?’
    next=[]
    start=0
    for end in range(len(elem)):
        if elem[end]!=elem[start]:
            next.append(str(end-start)+elem[start])
            start=end
    a.append(”.join(next))
print len(a[-1])

The output is:

5808

That's it. Coming up next, Level 11.

Read the rest of this entry »

Python Challenge level 9: “connect the dots”

Level 9 needs some more drawing.

Hint 1: first+second=?

import Image,ImageDraw
im = Image.new('RGB', (500,500))
draw = ImageDraw.Draw(im)

first=[146,399,163,403, ...]  # chunked
second=[156,141,165,135, ...] # chunked

for i in range(0, len(first), 2):
    draw.line(first[i:i + 4], fill='white')
for i in range(0, len(second), 2):
    draw.line(second[i:i + 4], fill='white')
im.save('09.jpg')

Is it a cow? Nope, it’s Level 10.

EDIT: Thanks to Meng Tan for the comment below. I didn’t know that PIL could (also) do that ;)

The script would be as follows:

import Image,ImageDraw
im = Image.new('RGB', (500,500))
draw = ImageDraw.Draw(im)
first=[146,399,163,403, ...]  # chunked
second=[156,141,165,135, ...] # chunked
draw.polygon(first,fill='white')
draw.polygon(second,fill='white')
im.save('09.jpg')
Read the rest of this entry »