from PIL import Image

image = Image.open("shuffle.png").convert("RGB")
X = 23
Y = 13
TOLERANCE = 20

def get_bordures(img):
    width, height = img.size
    left = list()
    top = list()
    right = list()
    bottom = list()
    for x in range(width):
        top.append(img.getpixel((x, 0)))
        bottom.append(img.getpixel((x, height-1)))
    for y in range(height):
        left.append(img.getpixel((0, y)))
        right.append(img.getpixel((width-1, y)))
    return left, top, right, bottom

def compare_bordure(b1, b2):
    res = 0
    for i in range(len(b1)):
        res += abs(b1[i][0] - b2[i][0]) + abs(b1[i][1] - b2[i][1]) + abs(b1[i][2] - b2[i][2])
    return res//len(b1)/3*100/256

width, height = image.size
w = width//X
h = height//Y

solution = Image.new("RGB", (width*2, height))

#create many small images
table = list()
for i in range(X*Y):
    img = Image.new("RGB", (w, h))
    x = (i//Y)*w
    y = (i%Y)*h
    tmp = image.crop((x, y, x+w, y+h))
    img.paste(tmp)
    left, top, right, bottom = get_bordures(img)
    table.append((img, left, top, right, bottom))

############################Try to find upper left image
# bordure_left_candidates = dict()
# for i in range(len(table)):
#     best = 100
#     for j in range(len(table)):
#         comp = compare_bordure(table[i][1], table[j][3])
#         if comp < best:
#             best = comp
#     bordure_left_candidates[i] = best
# print(bordure_left_candidates)
# print(max(bordure_left_candidates, key=bordure_left_candidates.get))

##############################Try to find top, bottom, left and right
# i = 5
# best_left = (None, 100)
# best_top = (None, 100)
# best_right = (None, 100)
# best_bottom = (None, 100)
# for j in range(len(table)):
#     comp = compare_bordure(table[i][2], table[j][4])
#     if comp < best_top[1]:
#         best_top = (j, comp)
#     comp = compare_bordure(table[i][4], table[j][2])
#     if comp < best_bottom[1]:
#         best_bottom = (j, comp)
#     comp = compare_bordure(table[i][1], table[j][3])
#     if comp < best_left[1]:
#         best_left = (j, comp)
#     comp = compare_bordure(table[i][3], table[j][1])
#     if comp < best_right[1]:
#         best_right = (j, comp)

# if best_top[1] < TOLERANCE:
#     solution.paste(table[best_top[0]][0], (w, 0))
# if best_left[1] < TOLERANCE:
#     solution.paste(table[best_left[0]][0], (0, h))
# solution.paste(table[i][0], (w, h))
# if best_right[1] < TOLERANCE:
#     solution.paste(table[best_right[0]][0], (w*2, h))
# if best_bottom[1] < TOLERANCE:
#     solution.paste(table[best_bottom[0]][0], (w, h*2))

#     solution.show()


##########################Try to find full rows
# table[10*13+5][0].show()

for k in (38, 19, 80, 81, 238, 31, 83, 73, 135, 232, 86):
    i = k
    print(i)
    solution.paste(table[i][0], (width,0))
    for x in range(1, X+1):
        best_right = (None, 100)
        for j in range(len(table)):
            comp = compare_bordure(table[i][3], table[j][1])
            if comp < best_right[1]:
                best_right = (j, comp)
        solution.paste(table[best_right[0]][0], (width+x*w,0))
        i = best_right[0]
    i = k
    for x in range(1, X+1):
        best_left = (None, 100)
        for j in range(len(table)):
            comp = compare_bordure(table[i][1], table[j][3])
            if comp < best_left[1]:
                best_left = (j, comp)
        solution.paste(table[best_left[0]][0], (width-x*w,0))
        i = best_left[0]
    solution.show()