Skip to content

Commit 67c7de7

Browse files
committed
Refactor solution to mission 24
1 parent 784e4ac commit 67c7de7

File tree

1 file changed

+54
-26
lines changed

1 file changed

+54
-26
lines changed

24-ambiguity.py

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,18 @@
1010

1111
# http://www.pythonchallenge.com/pc/hex/ambiguity.html
1212

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
1518
from io import BytesIO
1619
from PIL import Image
20+
from PIL import UnidentifiedImageError
1721
from zipfile import ZipFile
1822

23+
import logging
24+
1925

2026
turns_set = {(1, 0), (0, 1), (-1, 0), (0, -1)}
2127

@@ -29,15 +35,13 @@
2935

3036
def load_maze(url):
3137
"""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)))
3540
return maze.load(), maze.size
3641

3742

3843
def find_black_square(maze, size, row):
39-
width, _ = size
40-
for x in range(width):
44+
for x in range(size[0]):
4145
if maze[x, row][0] == 0:
4246
return x, row
4347

@@ -50,29 +54,53 @@ def explore(curr_dir, curr_square, maze):
5054
yield (x + dx, y + dy), (dx, dy)
5155

5256

53-
def tumble_down(maze, start, finish):
57+
@cached
58+
def tumble_down(maze, start, finish, cache):
5459
"""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
7098

7199

72100
maze, size = load_maze("http://www.pythonchallenge.com/pc/hex/ambiguity.html")
73101
start = find_black_square(maze, size, 0)
74102
finish = find_black_square(maze, size, size[1] - 1)
75103
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

Comments
 (0)