| import re |
| from .explainer_types import ExplainerResult, ExplainerScaffold |
|
|
|
|
| def _looks_like_ratio_question(text: str) -> bool: |
| low = (text or "").lower().strip() |
|
|
| if re.search(r"\b\d+\s*:\s*\d+\b", low): |
| return True |
|
|
| ratio_signals = [ |
| "ratio", |
| "proportion", |
| "for every", |
| "respectively", |
| "boys to girls", |
| "girls to boys", |
| "men to women", |
| "women to men", |
| "red to blue", |
| "blue to red", |
| "part to whole", |
| "part-to-whole", |
| "out of", |
| ] |
| return any(signal in low for signal in ratio_signals) |
|
|
|
|
| def _infer_ratio_subtype(text: str) -> str: |
| low = (text or "").lower() |
|
|
| if any(k in low for k in ["directly proportional", "inversely proportional", "proportion"]): |
| return "proportion" |
|
|
| if any(k in low for k in ["total", "sum", "combined", "altogether", "in all"]): |
| return "part_to_total" |
|
|
| if any( |
| k in low |
| for k in [ |
| "boys and girls", |
| "girls and boys", |
| "men and women", |
| "women and men", |
| "red and blue", |
| "blue and red", |
| "apples and oranges", |
| "cats and dogs", |
| "students and teachers", |
| ] |
| ): |
| return "group_ratio" |
|
|
| if any(k in low for k in ["for every", "ratio of", "respectively"]) or re.search(r"\b\d+\s*:\s*\d+\b", low): |
| return "ratio_parts" |
|
|
| return "generic_ratio" |
|
|
|
|
| def explain_ratio_question(text: str): |
| if not _looks_like_ratio_question(text): |
| return None |
|
|
| subtype = _infer_ratio_subtype(text) |
|
|
| result = ExplainerResult( |
| understood=True, |
| topic="ratio", |
| summary="This is a ratio problem. The main job is to preserve the order of the comparison and translate ratio parts into usable quantities with one shared scale factor.", |
| asks_for="the missing part, the total, or the quantity linked to the ratio", |
| plain_english="A ratio compares relative sizes, not actual amounts, so you usually need one shared multiplier before you can connect it to real quantities.", |
| ) |
|
|
| scaffold = ExplainerScaffold( |
| concept="A ratio compares quantities by relative size, not by actual amount.", |
| ask="Identify what each side of the ratio represents, keep the order exact, and decide whether the question wants a part, a total, a difference, or a scaled amount.", |
| target="Translate the ratio into variable-based quantities that connect to the condition in the question.", |
| answer_hidden=True, |
| solution_path_type=subtype, |
| ) |
|
|
| result.teaching_points = [ |
| "A ratio does not give actual quantities until a common scale factor is applied.", |
| "Most ratio questions become straightforward once each part is written using the same multiplier.", |
| "The order matters. Reversing the ratio changes the meaning of the setup.", |
| ] |
| result.givens = [ |
| "A comparison between two or more quantities.", |
| "An order that must be preserved exactly.", |
| ] |
| result.relationships = [ |
| "actual quantity = ratio part × common multiplier", |
| ] |
| result.needed_concepts = [ |
| "ratio order", |
| "shared multiplier", |
| "part-to-part versus part-to-whole structure", |
| ] |
| result.trap_notes = [ |
| "Reversing the order of the ratio.", |
| "Treating ratio numbers as final quantities instead of scaled parts.", |
| "Finding the multiplier but not returning to the quantity actually asked for.", |
| ] |
| result.strategy_hint = "Start by assigning the same multiplier to every part of the ratio." |
|
|
| if subtype == "ratio_parts": |
| scaffold.setup_actions = [ |
| "Write each ratio part using a common multiplier, such as ak and bk.", |
| "Keep the parts in the same order as the original ratio statement.", |
| "Use the condition in the question to connect those expressions to actual values.", |
| ] |
| scaffold.intermediate_steps = [ |
| "If one part is known, use it to find the common multiplier.", |
| "If a total is given, add the ratio expressions.", |
| "If a difference is given, subtract the relevant ratio expressions.", |
| ] |
| scaffold.first_move = "Rewrite each ratio term as a multiple of the same variable." |
| scaffold.next_hint = "Then connect those expressions to the value or condition given in the question." |
| scaffold.variables_to_define = [ |
| "Let the common multiplier be k.", |
| ] |
| scaffold.equations_to_form = [ |
| "amount = ratio part × k", |
| ] |
| scaffold.common_traps = [ |
| "Reversing the order of the ratio.", |
| "Treating the ratio parts as actual amounts immediately.", |
| "Using different multipliers for parts of the same ratio.", |
| ] |
| scaffold.key_operations = [ |
| "preserve order", |
| "introduce a shared multiplier", |
| "connect the ratio to the given condition", |
| ] |
| scaffold.hint_ladder = [ |
| "What does each side of the ratio represent?", |
| "Can you write both parts using the same multiplier?", |
| "What condition links those expressions to real values?", |
| ] |
|
|
| elif subtype == "part_to_total": |
| scaffold.setup_actions = [ |
| "Represent each part using the same multiplier.", |
| "Add the ratio parts to build the total.", |
| "Match the part or total expression to the stated condition.", |
| ] |
| scaffold.intermediate_steps = [ |
| "Translate the whole ratio into algebraic amounts first.", |
| "Use the sum of all parts when the question gives a total.", |
| "Check whether the final answer should be one part or the whole amount.", |
| ] |
| scaffold.first_move = "Turn the ratio into variable-based parts and combine them to form the total." |
| scaffold.next_hint = "Use the given total to solve for the shared multiplier." |
| scaffold.variables_to_define = [ |
| "Let the common multiplier be k.", |
| ] |
| scaffold.equations_to_form = [ |
| "total = (sum of ratio parts) × k", |
| ] |
| scaffold.common_traps = [ |
| "Using only one part when the condition refers to the whole total.", |
| "Leaving out one category when building the total.", |
| "Stopping after finding the multiplier instead of the requested amount.", |
| ] |
| scaffold.key_operations = [ |
| "write each part in terms of k", |
| "sum the parts", |
| "solve from the total condition", |
| ] |
| scaffold.hint_ladder = [ |
| "How many parts are there altogether?", |
| "Can you express the total in terms of k?", |
| "After finding k, which quantity does the question actually want?", |
| ] |
|
|
| elif subtype == "proportion": |
| scaffold.setup_actions = [ |
| "Identify which two ratios or rates are being set equal.", |
| "Match corresponding positions carefully.", |
| "Only form the equation once the correspondence is correct.", |
| ] |
| scaffold.intermediate_steps = [ |
| "Line up like-with-like before writing the proportion.", |
| "Check whether the quantities and units match properly.", |
| "Then simplify the resulting equation step by step.", |
| ] |
| scaffold.first_move = "Match the corresponding quantities in the two ratios." |
| scaffold.next_hint = "Once the matching is correct, write the equality between the two ratios." |
| scaffold.equations_to_form = [ |
| "first ratio = second ratio", |
| ] |
| scaffold.common_traps = [ |
| "Matching the wrong terms across the two ratios.", |
| "Using cross-multiplication before the setup is correct.", |
| "Ignoring whether the wording implies direct or inverse proportion.", |
| ] |
| scaffold.key_operations = [ |
| "match corresponding quantities", |
| "form the proportion", |
| "solve the resulting equation", |
| ] |
| scaffold.hint_ladder = [ |
| "Which terms correspond to each other?", |
| "Can you write the two ratios in the same order?", |
| "Only then should you solve the equation that results.", |
| ] |
|
|
| result.relationships = [ |
| "equivalent ratios represent the same multiplicative relationship", |
| "matching positions must stay consistent across the proportion", |
| ] |
| result.needed_concepts = [ |
| "equivalent ratios", |
| "corresponding terms", |
| "proportional structure", |
| ] |
|
|
| elif subtype == "group_ratio": |
| scaffold.setup_actions = [ |
| "Assign each group its ratio-based expression.", |
| "Use the stated total, difference, or known subgroup size to build an equation.", |
| "Solve for the common multiplier before finding the requested quantity.", |
| ] |
| scaffold.intermediate_steps = [ |
| "Make sure each category is represented exactly once.", |
| "Check whether the condition refers to one group or the whole set.", |
| "Return to the requested group after finding the multiplier.", |
| ] |
| scaffold.first_move = "Represent each group using the same scaling variable." |
| scaffold.next_hint = "Then use the condition involving the total or one subgroup to solve for that variable." |
| scaffold.variables_to_define = [ |
| "Let the common multiplier be k.", |
| ] |
| scaffold.equations_to_form = [ |
| "group amount = ratio part × k", |
| ] |
| scaffold.common_traps = [ |
| "Using separate multipliers for groups in the same ratio.", |
| "Answering with the multiplier instead of the group requested.", |
| "Losing track of the original ratio order when translating categories.", |
| ] |
| scaffold.key_operations = [ |
| "assign each group an expression", |
| "use the total or subgroup condition", |
| "return to the requested category", |
| ] |
| scaffold.hint_ladder = [ |
| "What does each group correspond to in the ratio?", |
| "Can you write each group in terms of k?", |
| "Which condition lets you solve for k?", |
| ] |
|
|
| else: |
| scaffold.setup_actions = [ |
| "Identify what each part of the ratio refers to.", |
| "Translate the ratio into algebraic quantities using one shared scale factor.", |
| "Use the stated condition to solve for that scale factor.", |
| ] |
| scaffold.intermediate_steps = [ |
| "Use addition if a total is involved.", |
| "Use subtraction if a difference is involved.", |
| "Check carefully which final quantity the question wants.", |
| ] |
| scaffold.first_move = "Start by assigning a shared multiplier to the ratio parts." |
| scaffold.next_hint = "Then use the given condition to turn the ratio setup into an equation." |
| scaffold.variables_to_define = [ |
| "Let the common multiplier be k.", |
| ] |
| scaffold.equations_to_form = [ |
| "actual quantity = ratio part × k", |
| ] |
| scaffold.common_traps = [ |
| "Reversing the order of the ratio.", |
| "Not using one shared multiplier.", |
| "Stopping at the multiplier instead of the requested quantity.", |
| ] |
| scaffold.key_operations = [ |
| "identify the parts", |
| "use one shared multiplier", |
| "build the equation from the given condition", |
| ] |
| scaffold.hint_ladder = [ |
| "What exactly is being compared?", |
| "Can you express the ratio parts using k?", |
| "What given condition turns that setup into an equation?", |
| ] |
|
|
| result.scaffold = scaffold |
| result.meta = { |
| "intent": "explain_question", |
| "bridge_ready": True, |
| "hint_style": "step_ready", |
| "subtype": subtype, |
| } |
|
|
| return result |