Tags: image python csv png pil
Rating:
Description:
Can you put this puzzle back together?
172.31.0.10/puzzletime_7e4148595c3837b0f14598eb0f21b272
The offered file was a gzipped CSV with 48853 lines, of the format:
Value,Right Edge Id,Bottom Edge Id,Left Edge Id,Top Edge Id
0x111811,105686801264,887560873655,312990448974,548925778434
0x384126,650152958814,52199694120,211764317707,433816471245
0xc3bab1,5909959089,950174968371,749641960137,537615257711
0x3e4a24,916756480148,216091138945,804727523965,811655369006
0x3a4d31,426308808667,931973485956,787722656299,55311493582
0xb6aa92,776257260469,503239175816,128107297285,702022168178
0x516437,414462949367,364785201606,944310974796,866635322023
0x1b291a,105359185807,715972077437,104869394726,611561837736
The first column, being a 3-byte hex value, immediately jumped out as RGB.
Grepping around for a random sampling of "Edge Id"s revealed that most edges only appeared twice in the file, a "Right Edge Id" occuring with a matching "Left Edge Id" on another line.
Needing a place to start, we guessed that "0" might be the Edge Id at the border of the image, and a quick grep revealed that to be correct:
# Edges:
0x121d15,0,974309486812,473992437188,497944637480
0x1a251f,569290835136,91408348362,0,738900157213
0x1d1f1a,404534979934,0,55925662970,84026215997
0x6e8f98,886611260159,159819253788,530007324828,0
# Corners:
0x799394,286014760927,696891703802,0,0
0x141913,854263618885,0,0,838963856720
0x272727,0,0,898925785824,245795270114
0x252e1d,0,420247040560,174936345665,0
By looking for how many edges occurred in a given slot, we can find the size of the image:
$ gunzip < puzzletime_7e4148595c3837b0f14598eb0f21b272 | grep '^[^,]\+,0,' | wc -l
207
$ gunzip < puzzletime_7e4148595c3837b0f14598eb0f21b272 | grep '^[^,]\+,[^,]\+,0,' | wc -l
236
By writing a program that keeps track of known edges, starting with the top-left edges of `(0,0)`, we were able to look up and render each pixel into our output image:
import struct
from PIL import Image, ImageDraw
size = (207, 236)
image = Image.new('RGB', size)
draw = ImageDraw.Draw(image)
def unpackColor(color):
(r,g,b) = struct.unpack('BBB', color[2:].decode('hex'))
return (r,g,b)
points = dict()
tops = dict()
lefts = dict()
def _color(elem): return elem[0]
def _right(elem): return elem[1]
def _bottom(elem): return elem[2]
def _left(elem): return elem[3]
def _top(elem): return elem[4]
# Read all input into `points`, tracking the bottom and left edges
with open('data.csv') as data:
data.readline()
i = 0
for line in data:
elem = line.strip().split(',')
points[(_left(elem),_top(elem))] = elem
tops.setdefault(_top(elem), []).append(elem)
lefts.setdefault(_right(elem), []).append(elem)
wants = dict()
wants[('0', '0')] = (0,0)
while wants:
for idx in wants.keys():
if idx not in points:
print "Error:", idx
del wants[idx]
continue
elem = points[idx]
(x, y) = wants[(_left(elem),_top(elem))]
print ' ', x, y, elem
draw.point((x,y), unpackColor(_color(elem)))
if _bottom(elem) != '0':
wants[(_left(tops[_bottom(elem)][0]), _bottom(elem))] = (x, y+1)
if _right(elem) != '0':
wants[(_right(elem), _top(lefts[_right(elem)][0]))] = (x+1, y)
del wants[idx]
image.save('out.png')
print "Done"
After running the program, we were greeted with a picture of a goat, with the key written across the top.
Answer:
PuzzleGoatKeyIsBestKey