from pathlib import Path from PIL import Image, ImageDraw, ImageFont import random import json TEXT_FONT = Path(__file__).parent / "assets" / "FreeSerifBold.otf" CHARSET = tuple('ABCDEFGHIJKLMNOPQRSTUVWXYZ') DIGITS = tuple('0123456789') INPUT_TYPE = "text" INPUT_HINT = "enter text decoded from the number" def generate_puzzle_fields(WORD_LENGTH): """Create new puzzle for a player""" chars = random.sample(CHARSET, len(CHARSET)) digits = [''.join(random.sample(DIGITS, 3)) for _ in range(len(CHARSET))] lookup = dict(zip(chars, digits)) word = ''.join(random.sample(CHARSET, WORD_LENGTH)) word_solution = '' for letter in word: word_solution += str(lookup[letter]) coded_word = word solution = word_solution return dict( text=json.dumps(dict(rows=[chars, digits], coded_word=coded_word)), solution=solution, ) def is_correct(response, puzzle): return puzzle.solution.lower() == response.lower() TEXT_SIZE = 32 TEXT_PADDING = TEXT_SIZE CELL_DIM = TEXT_SIZE + TEXT_PADDING * 2 MID = CELL_DIM * 0.5 def render_image(puzzle): data = json.loads(puzzle.text) data1 = { 'rows': [data['rows'][0][:13], data['rows'][1][:13]] } data2 = { 'rows': [data['rows'][0][13:], data['rows'][1][13:]] } # Calculate the table dimensions based on data table_width = len(data1['rows'][0]) * CELL_DIM table_height = len(data1['rows']) * CELL_DIM font = ImageFont.truetype(str(TEXT_FONT), TEXT_SIZE) font_large = ImageFont.truetype(str(TEXT_FONT), (TEXT_SIZE) * 2) img_w = (CELL_DIM * int(len(CHARSET) / 2)) + 1 # CORRECTS INCOMPLETE GRID # 4 because 2 rows + blank space + row for coded word img_h = (CELL_DIM * 7) + 1 # CORRECTS INCOMPLETE GRID image = Image.new("RGB", (img_w, img_h), (255, 255, 255)) draw = ImageDraw.Draw(image) # Loop through the rows and columns to draw the first 2x4 table for rownum, row in enumerate(data1['rows']): for colnum, char in enumerate(row): x = colnum * CELL_DIM y = rownum * CELL_DIM draw.rectangle([x, y, x + CELL_DIM, y + CELL_DIM], outline='black') draw.text((x + MID, y + MID), char, font=font, fill='black', anchor="mm") # Add a separation row for colnum in range(len(data1['rows'][0])): x = colnum * CELL_DIM y = 2 * table_height # Position the separation row below the first table draw.rectangle([x, y, x + CELL_DIM, y + CELL_DIM], outline='black') # Loop through the rows and columns to draw the second 2x4 table for rownum, row in enumerate(data2['rows']): for colnum, char in enumerate(row): x = colnum * CELL_DIM y = (rownum + 3) * CELL_DIM # Shift the y position for the second table draw.rectangle([x, y, x + CELL_DIM, y + CELL_DIM], outline='black') draw.text((x + MID, y + MID), char, font=font, fill='black', anchor="mm") coded_word = data['coded_word'] w, h = draw.textsize(coded_word) draw.text( ((img_w - w) / 2, image.height - MID), text="'word': " + data['coded_word'], font=font_large, fill='black', anchor="mm", ) return image