# -*- coding: utf-8 -*- import json, csv, copy, random from collections import defaultdict def validate_stage(stage): grid_size = stage['gridSize'] clues = stage['clues'] grid = {} if len(clues) < 3: return False, f"Stage {stage.get('stageNumber')}: Too few clues ({len(clues)})" word_connections = {c['id']: set() for c in clues} for clue in clues: word = clue['word'] length = clue['length'] r = clue['startRow'] c = clue['startCol'] direction = clue['direction'] if len(word) != length: return False, f"Stage {stage.get('stageNumber')} Clue {clue['id']}: word '{word}' len {len(word)} != length {length}" if length < 2: return False, f"Stage {stage.get('stageNumber')} Clue {clue['id']}: 1-letter word '{word}' not allowed" for i, ch in enumerate(word): curr_r = r + (i if direction == 'DOWN' else 0) curr_c = c + (i if direction == 'ACROSS' else 0) if curr_r < 0 or curr_r >= grid_size or curr_c < 0 or curr_c >= grid_size: return False, f"Stage {stage.get('stageNumber')} Clue {clue['id']}: '{word}' char '{ch}' at ({curr_r}, {curr_c}) out of bounds ({grid_size}x{grid_size})" if (curr_r, curr_c) in grid: existing_ch, existing_id = grid[(curr_r, curr_c)] if existing_ch != ch: return False, f"Stage {stage.get('stageNumber')} CLASH at ({curr_r}, {curr_c}): existing '{existing_ch}' ({existing_id}) vs '{ch}' in {clue['id']} ('{word}')" word_connections[clue['id']].add(existing_id) word_connections[existing_id].add(clue['id']) else: grid[(curr_r, curr_c)] = (ch, clue['id']) for cid, conns in word_connections.items(): if not conns: return False, f"Stage {stage.get('stageNumber')} Clue {cid} has no intersections!" return True, "OK" print("Test generator script ready.")