worked on the chall

This commit is contained in:
2026-01-08 09:42:09 +01:00
parent 6d8117c53c
commit ee95f4df4f
14 changed files with 313 additions and 232 deletions

View File

@@ -1,13 +1,13 @@
from logging import disable
from PIL import Image
from pyzbar.pyzbar import decode
import itertools
from math import perm
from tqdm import tqdm
import numpy as np
from multiprocessing import Pool
from math import perm
import sys
NUM_PIECES_WIDTH = 4
NUM_PIECES_HEIGHT = 3
BOX_SIZE = 2
TILE = 78
# 7x7 finder, upscaled to 14x14 (black=1, white=0)
@@ -40,23 +40,17 @@ def cut_pieces(image):
# Get the size of the image
width, height = image.size
# Calculate the size of each grid cell
cell_width = width // NUM_PIECES_WIDTH
cell_height = height // NUM_PIECES_HEIGHT
if width == height:
NUM_PIECES_WIDTH = 3
else:
NUM_PIECES_WIDTH = 4
NUM_PIECES_HEIGHT = 3
pieces = []
# Split the original image into 12 pieces
for i in range(NUM_PIECES_WIDTH * NUM_PIECES_HEIGHT):
# Calculate the coordinates of the current grid cell
x1 = (i % NUM_PIECES_WIDTH) * cell_width
y1 = (i // NUM_PIECES_WIDTH) * cell_height
x2 = x1 + cell_width
y2 = y1 + cell_height
# Crop the corresponding part of the original image
cropped_piece = image.crop((x1, y1, x2, y2))
pieces.append(cropped_piece)
for x, y in [(x, y) for x in range(NUM_PIECES_WIDTH) for y in range(NUM_PIECES_HEIGHT)]:
pieces.append(image.crop((x * TILE, y * TILE, x * TILE + TILE, y * TILE + TILE)))
return pieces
@@ -72,7 +66,6 @@ def finder_corner_exact(tile_bw):
'TL': tile_bw[0:H, 0:W ],
'TR': tile_bw[0:H, TILE-W:TILE ],
'BL': tile_bw[TILE-H:TILE, 0:W ],
'BR': tile_bw[TILE-H:TILE, TILE-W:TILE ],
}
for corner, crop in crops.items():
if np.array_equal(crop, TEMPLATE):
@@ -90,11 +83,33 @@ def three_tiles_with_finders(tiles):
break
return hits
def solve_combo(combo):
"""
Function to be executed by each process in the pool.
"""
a, b, c, d, e, f = combo
# Assuming `new_image` is a base image you can copy or an in-memory image object.
# You may need to pass `new_image` to the function or have it loaded by each process.
local_image = new_image.copy() # Make a copy to avoid race conditions
local_image.paste(a, (78, 0))
local_image.paste(b, (0, 78))
local_image.paste(c, (78, 78))
local_image.paste(d, (156, 78))
local_image.paste(e, (78, 156))
local_image.paste(f, (156, 156))
output = decodeQRCode(local_image)
if output:
return output
return None
if __name__ == "__main__":
img = Image.open("./scrambled_test_qr_code.png")
def main(img_path="student_fair/secret_message.png", verbose=True):
img = Image.open(img_path)
global new_image
new_image = Image.new("RGB", (img.height, img.height))
pieces = cut_pieces(img)
corners = three_tiles_with_finders(pieces)
@@ -110,22 +125,27 @@ if __name__ == "__main__":
pieces = [piece for piece in pieces if piece not in [tile for tile, _ in corners]]
assert len(pieces) == 9
new_image.show()
possible_combos = itertools.permutations(pieces, 6)
num_possible_combos = perm(len(pieces), 6)
print(f"Testing {num_possible_combos} combinations")
for a,b,c,d,e,f in tqdm(possible_combos, total=num_possible_combos):
new_image.paste(a, (78, 0))
new_image.paste(b, (0, 78))
new_image.paste(c, (78, 78))
new_image.paste(d, (156, 78))
new_image.paste(e, (78, 156))
new_image.paste(f, (156, 156))
output = decodeQRCode(new_image)
if output:
print(output)
result = None
MAX_WORKER = 6
print(decodeQRCode(img))
# Use `multiprocessing.Pool` with the number of available cores
with Pool(MAX_WORKER) as pool:
# `imap_unordered` returns results as they are completed.
# This is a lazy iterator, so it doesn't create all combos at once.
# `tqdm` can still be used to show progress.
for result in tqdm(pool.imap_unordered(solve_combo, possible_combos), total=perm(len(pieces), 6), disable=(not verbose)):
if result:
if verbose:
print(f"QR Code decoded: {result}")
pool.terminate() # Stop all worker processes
break
return result
if __name__ == "__main__":
main()