10
10
11
11
# http://www.pythonchallenge.com/pc/hex/ambiguity.html
12
12
13
- from auth import open_url
14
- from auth import read_riddle
13
+ from auth import get_last_src_url
14
+ from auth import read_url
15
+ from cache import autocached
16
+ from cache import cached
17
+ from image import image_to_text
15
18
from io import BytesIO
16
19
from PIL import Image
20
+ from PIL import UnidentifiedImageError
17
21
from zipfile import ZipFile
18
22
23
+ import logging
24
+
19
25
20
26
turns_set = {(1 , 0 ), (0 , 1 ), (- 1 , 0 ), (0 , - 1 )}
21
27
29
35
30
36
def load_maze (url ):
31
37
"""Fetches and loads maze.png then returns its pixels and size"""
32
- riddle_source = read_riddle (url )
33
- url = url .replace ("ambiguity.html" , riddle_source .split ('src="' )[- 1 ].split ('"' )[0 ])
34
- maze = Image .open (open_url (url ))
38
+ maze_url = get_last_src_url (url )
39
+ maze = Image .open (BytesIO (read_url (maze_url )))
35
40
return maze .load (), maze .size
36
41
37
42
38
43
def find_black_square (maze , size , row ):
39
- width , _ = size
40
- for x in range (width ):
44
+ for x in range (size [0 ]):
41
45
if maze [x , row ][0 ] == 0 :
42
46
return x , row
43
47
@@ -50,29 +54,53 @@ def explore(curr_dir, curr_square, maze):
50
54
yield (x + dx , y + dy ), (dx , dy )
51
55
52
56
53
- def tumble_down (maze , start , finish ):
57
+ @cached
58
+ def tumble_down (maze , start , finish , cache ):
54
59
"""Tumbles down the maze in a DFS fashion"""
55
- data = []
56
- visited , next_squares = {start }, [(start , 0 , (0 , 1 ))]
57
- while next_squares :
58
- curr_square , steps , curr_dir = next_squares .pop ()
59
- if curr_square == finish :
60
- break
61
- # Deadend? Remove all steps in wrong direction
62
- del data [steps :]
63
- visited .add (curr_square )
64
- for square , direction in explore (curr_dir , curr_square , maze ):
65
- if square not in visited :
66
- next_squares .append ((square , steps + 1 , direction ))
67
- data .append (maze [curr_square ][0 ])
68
- # Skip every even-indexed pixel 🤷🏻♂️
69
- return bytes (data [1 ::2 ])
60
+ if "result_data" not in cache :
61
+ data , visited , next_squares = [], {start }, [(start , 0 , (0 , 1 ))]
62
+ while next_squares :
63
+ curr_square , steps , curr_dir = next_squares .pop ()
64
+ if curr_square == finish :
65
+ break
66
+ # Deadend? Remove all steps in wrong direction
67
+ del data [steps :]
68
+ visited .add (curr_square )
69
+ for square , direction in explore (curr_dir , curr_square , maze ):
70
+ if square not in visited :
71
+ next_squares .append ((square , steps + 1 , direction ))
72
+ data .append (maze [curr_square ][0 ])
73
+ # Skip every even-indexed pixel 🤷
74
+ cache ["result_data" ] = bytes (data [1 ::2 ])
75
+ return cache ["result_data" ]
76
+
77
+
78
+ def extract_image (data ):
79
+ """Tries and extracts the image inside data (which is a zipfile)"""
80
+ with ZipFile (BytesIO (data )) as zip_file :
81
+ for name in zip_file .namelist ()[::- 1 ]:
82
+ try :
83
+ return Image .open (BytesIO (zip_file .read (name )))
84
+ except UnidentifiedImageError :
85
+ logging .warning ("%s does not seem to be an image" , name )
86
+
87
+
88
+ @autocached
89
+ def crop_blue_only (image ):
90
+ """Crops the image and creates a new one with only the bluest pixels"""
91
+ img = Image .new ("L" , (2 * image .width // 3 + 1 , image .height // 2 ))
92
+ for y in range (image .height // 2 , image .height ):
93
+ for x in range (image .width // 3 , image .width ):
94
+ r , g , b = image .getpixel ((x , y ))
95
+ if b > 1.2 * r and b > 1.2 * g :
96
+ img .putpixel ((x - image .width // 3 , y - image .height // 2 ), b )
97
+ return img
70
98
71
99
72
100
maze , size = load_maze ("http://www.pythonchallenge.com/pc/hex/ambiguity.html" )
73
101
start = find_black_square (maze , size , 0 )
74
102
finish = find_black_square (maze , size , size [1 ] - 1 )
75
103
data = tumble_down (maze , start , finish )
76
- with ZipFile ( BytesIO ( data ), "r" ) as zip_file :
77
- print ( "Check {} and note {} (why is it there?)" . format ( * zip_file . namelist ()) )
78
- zip_file . extractall ( )
104
+ image = extract_image ( data )
105
+ new_image = crop_blue_only ( image )
106
+ print ( image_to_text ( new_image ) )
0 commit comments