"""Game logic for ValluvarAI guessing game.""" import random from typing import Any, Final from config import ( _MAX_GENERATION_ATTEMPTS, _TEMP_INCREMENT, _MAX_TEMP, _MAX_SEED, _GENERATE_MAX_TOKENS, _BASE_TEMP, ) from model_engine import generate, model, stoi, itos from kural_engine import ( _extract_tamil_couplet, _is_couplet_in_original, _is_valid_kural_structure, format_kural, _extract_kural_lines, _get_kurals_db, ORIGINAL_TEXT, ) _SYNTHETIC_FALLBACKS: Final = ( "கற்க கசடறக் கற்பவர் கற்றபின்\nநிற்க அதற்கு தக", "அன்பும் அறனும் உடைத்தாம் முகத்தில்\nஇன்பும் இறைவன் துணை", "அறம் செய்யும் உள்ளத்தார் வாழ்வின்\nஇன்பம் என்றும் தங்கும்", "கல்வி கற்பவர் கண்ணோட்டம் கொள்ளின்\nஅறிவு வளர்ந்து வரும்", "நல்லாறு நின்றார் நிலைமை சொல்லுங்கால்\nசொல்லுக சான்றோர் முன்", ) _PROMPTS: Final = ( "கடவுள் வாழ்த்து", "நட்பு", "அறன்", "வான் சிறப்பு", "அரசியல்", "பொருள்", "கல்வி", "காதல்", ) def new_round() -> tuple[str, dict[str, Any] | None, str]: """Start a new guessing round. Returns Tamil couplet, state, and cleared reveal.""" is_real = random.choice((True, False)) if is_real: kural = random.choice(_get_kurals_db()) tamil_only = f"{kural['tamil_1']}\n{kural['tamil_2']}" state = {"is_real": True, "data": kural} return tamil_only, state, "" prompt = random.choice(_PROMPTS) couplet: str | None = None ai_kural_raw = "" attempts = 0 temp = _BASE_TEMP for attempt in range(_MAX_GENERATION_ATTEMPTS): attempts = attempt + 1 temp = min(_BASE_TEMP + attempt * _TEMP_INCREMENT, _MAX_TEMP) seed = random.randint(1, _MAX_SEED) ai_kural_raw = generate(model, prompt, stoi, itos, max_new_tokens=_GENERATE_MAX_TOKENS, temperature=temp, seed=seed) couplet = _extract_tamil_couplet(ai_kural_raw) if couplet and not _is_couplet_in_original(couplet, ORIGINAL_TEXT): if _is_valid_kural_structure(couplet.split("\n")): break if not couplet or _is_couplet_in_original(couplet, ORIGINAL_TEXT): tamil_only = random.choice(_SYNTHETIC_FALLBACKS) english_lines: list[str] = [] confidence = 50 attempts = _MAX_GENERATION_ATTEMPTS else: formatted = format_kural(ai_kural_raw) tamil_lines, english_lines = _extract_kural_lines(formatted.split("\n")) tamil_only = "\n".join(tamil_lines[:2]) if len(tamil_lines) >= 2 else formatted confidence = max(20, 100 - (attempts - 1) * 6) state = { "is_real": False, "data": { "prompt": prompt, "temperature": temp, "attempts": attempts, "tamil_couplet": tamil_only, "english_lines": english_lines[:2], "confidence": confidence, }, } return tamil_only, state, "" def check_guess(guess: str, state: dict[str, Any] | None) -> str: """Check the user's guess and return reveal markdown.""" if not state: return "⚠️ Click **Next Couplet** to start!" is_real = state["is_real"] correct = (guess == "valluvar" and is_real) or (guess == "ai" and not is_real) verdict = "✅ Correct!" if correct else "❌ Wrong!" data = state["data"] if is_real: return ( f"## {verdict}\n\n" f"### 📖 Real Thirukkural #{data['number']}\n\n" f"**Chapter:** {data['chapter_tamil']} — *{data['chapter_english']}*\n\n" f"**Meaning:**\n> {data['english_1']}\n> {data['english_2']}" ) eng_text = "\n> ".join(data["english_lines"]) if data["english_lines"] else "*(No translation generated)*" return ( f"## {verdict}\n\n" f"### 🤖 AI Generated\n\n" f"**Prompt:** `{data['prompt']}` \n" f"**Temperature:** {data['temperature']:.2f} \n" f"**Generation attempts:** {data['attempts']} \n" f"**Confidence:** {data['confidence']}% \n\n" f"**Model's translation:**\n> {eng_text}" )