| import re |
| from .explainer_types import ExplainerResult, ExplainerScaffold |
|
|
|
|
| def _looks_like_ratio_question(text: str) -> bool: |
| low = (text or "").lower() |
|
|
| if re.search(r"\b\d+\s*:\s*\d+\b", low): |
| return True |
| if "for every" in low: |
| return True |
| if "ratio" in low or "proportion" in low: |
| return True |
|
|
| return False |
|
|
|
|
| def _infer_ratio_subtype(text: str) -> str: |
| low = (text or "").lower() |
|
|
| if any(k in low for k in ["for every", "ratio of", "respectively"]): |
| return "ratio_parts" |
| if any(k in low for k in ["total", "sum", "combined"]): |
| return "part_to_total" |
| if any(k in low for k in ["proportion", "directly proportional", "inversely proportional"]): |
| return "proportion" |
| if any(k in low for k in ["mixture", "men and women", "boys and girls", "red and blue", "apples and oranges"]): |
| return "group_ratio" |
| 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 ratio and convert ratio parts into actual quantities using one shared multiplier." |
| ) |
|
|
| scaffold = ExplainerScaffold( |
| concept="A ratio compares quantities by relative size, not by actual amount.", |
| ask="Decide what each side of the ratio refers to, keep the order exact, and determine whether the question wants one part, a total, a difference, or a scaled version.", |
| target="Translate the ratio into variable-based quantities that can be linked to the condition in the question.", |
| answer_hidden=True, |
| ) |
|
|
| teaching_points = [ |
| "A ratio does not give actual quantities until a common scale factor is applied.", |
| "Most ratio questions become simple algebra once each part is written in terms of the same multiplier.", |
| "The order matters. Reversing the ratio changes the meaning of the whole setup." |
| ] |
|
|
| if subtype == "ratio_parts": |
| scaffold.setup_actions = [ |
| "Write each ratio part using a common multiplier such as ak and bk.", |
| "Keep the terms 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, solve for the multiplier first.", |
| "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 = [ |
| "amounts = ratio parts × common multiplier" |
| ] |
| scaffold.common_traps = [ |
| "Reversing the order of the ratio.", |
| "Treating the ratio numbers as final quantities instead of scaled parts.", |
| "Forgetting that different parts must all use the same multiplier." |
| ] |
|
|
| elif subtype == "part_to_total": |
| scaffold.setup_actions = [ |
| "Represent each part with a shared multiplier.", |
| "Add the ratio parts to represent the total.", |
| "Match the part or total expression to the given condition." |
| ] |
| scaffold.intermediate_steps = [ |
| "Translate the whole ratio into algebraic amounts first.", |
| "Use the sum of all parts for the total.", |
| "Check whether the question asks for one component or the overall total." |
| ] |
| scaffold.first_move = "Turn the ratio into variable-based amounts and add them to get the total structure." |
| 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 all ratio parts × k" |
| ] |
| scaffold.common_traps = [ |
| "Using only one part instead of the full sum when a total is given.", |
| "Dropping one category from the total.", |
| "Solving for the multiplier and forgetting to return to the quantity actually asked for." |
| ] |
|
|
| elif subtype == "proportion": |
| scaffold.setup_actions = [ |
| "Identify which two ratios or rates are being set equal.", |
| "Preserve matching positions carefully.", |
| "Use cross-multiplication only after the correspondence is correct." |
| ] |
| scaffold.intermediate_steps = [ |
| "Line up like-with-like before building the proportion.", |
| "Check units or roles so the comparison makes sense.", |
| "Then simplify the resulting equation." |
| ] |
| scaffold.first_move = "Match the corresponding quantities in the two ratios." |
| scaffold.next_hint = "Once the matching is correct, form the equation between the two ratios." |
| scaffold.equations_to_form = [ |
| "first ratio = second ratio" |
| ] |
| scaffold.common_traps = [ |
| "Matching the wrong terms across the two ratios.", |
| "Cross-multiplying before the setup is correct.", |
| "Ignoring whether the problem is direct or inverse proportion." |
| ] |
|
|
| elif subtype == "group_ratio": |
| scaffold.setup_actions = [ |
| "Assign each group its ratio-based expression.", |
| "Use the stated total, difference, or known subgroup size to create 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 is about the whole group or one subgroup.", |
| "Return to the requested category at the end." |
| ] |
| scaffold.first_move = "Represent each group using the same scaling variable." |
| scaffold.next_hint = "Then use the condition involving the total or one group to solve for that variable." |
| scaffold.variables_to_define = [ |
| "Let the common multiplier be k." |
| ] |
| scaffold.common_traps = [ |
| "Using separate multipliers for parts of the same ratio.", |
| "Answering with the multiplier instead of the requested group amount.", |
| "Losing the original ratio order when translating categories." |
| ] |
|
|
| else: |
| scaffold.setup_actions = [ |
| "Identify what each term in the ratio represents.", |
| "Translate the ratio into algebraic quantities with a common scale factor.", |
| "Use the stated condition to solve for the scale factor." |
| ] |
| scaffold.intermediate_steps = [ |
| "Use the sum if a total is involved.", |
| "Use subtraction if a difference is involved.", |
| "Check 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.common_traps = [ |
| "Reversing the order of the ratio.", |
| "Not using one shared multiplier.", |
| "Stopping at the multiplier instead of the requested quantity." |
| ] |
|
|
| result.teaching_points = teaching_points |
| result.scaffold = scaffold |
| result.meta = { |
| "intent": "explain_question", |
| "bridge_ready": True, |
| "hint_style": "step_ready", |
| "subtype": subtype, |
| } |
| return result |