File size: 7,958 Bytes
3a0ff5a 10fdac3 508bc51 9e67f64 3a0ff5a 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 3a0ff5a 508bc51 9e67f64 3a0ff5a 508bc51 9e67f64 3a0ff5a 508bc51 3a0ff5a 9e67f64 3a0ff5a 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 10fdac3 508bc51 10fdac3 508bc51 10fdac3 508bc51 10fdac3 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 508bc51 9e67f64 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | 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 |