from collections import Counter from app.schemas.visual_lesson import ArrayAlgorithmSpec from app.services.array_algorithm_compiler import ArrayAlgorithmCompiler, SEARCH_ALGORITHMS class ArrayAlgorithmValidationError(ValueError): pass class ArrayAlgorithmValidator: def __init__(self, compiler: ArrayAlgorithmCompiler) -> None: self.compiler = compiler def validate(self, spec: ArrayAlgorithmSpec) -> None: if not 2 <= len(spec.input_values) <= 32 or spec.primary_algorithm not in spec.enabled_algorithms: raise ArrayAlgorithmValidationError("Array algorithm inputs are invalid") if "binary_search" in spec.enabled_algorithms and spec.input_values != sorted(spec.input_values): raise ArrayAlgorithmValidationError("Binary search cannot run on an unsorted array") claims = {claim.claim_id for claim in spec.evidence_claims} if not {"array-sorting", "array-search", "array-binary-precondition"} <= claims: raise ArrayAlgorithmValidationError("Array algorithm definitions are missing") compiled = self.compiler.compile_spec(spec) for branch in compiled.branches: if branch.algorithm in SEARCH_ALGORITHMS: expected = next((index for index, value in enumerate(spec.input_values) if value == spec.search_target), -1) if branch.found_index != expected and not (branch.algorithm == "binary_search" and branch.found_index >= 0 and spec.input_values[branch.found_index] == spec.search_target): raise ArrayAlgorithmValidationError("Search result validation failed") elif branch.final_values != sorted(spec.input_values) or Counter(branch.final_values) != Counter(spec.input_values): raise ArrayAlgorithmValidationError("Sorting result validation failed")