File size: 12,255 Bytes
7a2d839 37e4b67 7a2d839 2660a67 a5d5985 7a2d839 a5d5985 2660a67 a5d5985 2660a67 82ffe01 2660a67 a5d5985 2660a67 a5d5985 2660a67 7a2d839 2660a67 7a2d839 a5d5985 2660a67 a5d5985 7a2d839 a5d5985 2660a67 a5d5985 82ffe01 a5d5985 7a2d839 2660a67 5be6cc2 2660a67 5be6cc2 2660a67 5be6cc2 2660a67 5be6cc2 2660a67 a5d5985 2660a67 7a2d839 2660a67 a5d5985 2660a67 a5d5985 2660a67 a5d5985 2660a67 a5d5985 2660a67 a5d5985 2660a67 a5d5985 2660a67 a5d5985 82ffe01 2660a67 a5d5985 82ffe01 2660a67 a5d5985 7a2d839 2660a67 a5d5985 2660a67 a5d5985 2660a67 a5d5985 2660a67 a5d5985 2660a67 a5d5985 82ffe01 2660a67 82ffe01 2660a67 a5d5985 7a2d839 2660a67 a5d5985 2660a67 a5d5985 2660a67 a5d5985 82ffe01 2660a67 82ffe01 2660a67 a5d5985 7a2d839 2660a67 a5d5985 2660a67 a5d5985 2660a67 a5d5985 2660a67 82ffe01 2660a67 82ffe01 2660a67 a5d5985 7a2d839 2660a67 a5d5985 2660a67 a5d5985 2660a67 a5d5985 82ffe01 2660a67 82ffe01 2660a67 a5d5985 7a2d839 a5d5985 2660a67 a5d5985 2660a67 a5d5985 2660a67 82ffe01 2660a67 82ffe01 2660a67 a5d5985 7a2d839 a5d5985 5be6cc2 a5d5985 | 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 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | import re
from .explainer_types import ExplainerResult, ExplainerScaffold
_PERCENT_PATTERNS = [
r"\bpercent\b",
r"\bpercentage\b",
r"\bwhat percent\b",
r"\bpercent of\b",
r"\bpercent greater than\b",
r"\bpercent less than\b",
r"\bincrease(?:d)? by \d+ ?%\b",
r"\bdecrease(?:d)? by \d+ ?%\b",
r"\bdiscount\b",
r"\bmarkup\b",
r"\binterest\b",
r"\btax\b",
r"\btip\b",
r"\bprofit margin\b",
r"\bcommission\b",
r"\bpart of\b",
r"\bof a number\b",
]
def _looks_like_percent_question(text: str) -> bool:
low = (text or "").lower()
if "%" in low:
return True
return any(re.search(p, low) for p in _PERCENT_PATTERNS)
def _infer_percent_subtype(text: str) -> str:
low = (text or "").lower()
if any(k in low for k in ["increase", "decrease", "increased", "decreased", "percent change", "changed by"]):
return "percent_change"
if any(k in low for k in ["discount", "sale", "off", "markdown"]):
return "discount"
if any(k in low for k in ["interest", "simple interest", "compound interest"]):
return "interest"
if any(k in low for k in ["tax", "vat", "tip", "gratuity"]):
return "tax_tip"
if any(k in low for k in ["what percent", "is what percent of", "as a percent of"]):
return "percent_of_percent"
if any(k in low for k in ["percent of", "of a number", "% of"]):
return "basic_percent"
return "generic_percent"
def explain_percent_question(text: str):
if not _looks_like_percent_question(text):
return None
subtype = _infer_percent_subtype(text)
result = ExplainerResult(
understood=True,
topic="percent",
summary="This is a percent problem. The key is to identify which quantity is the base, which is the compared amount, and what role the percent is playing.",
asks_for="the missing value, the percent itself, or the final changed total",
plain_english="Percent means per hundred, so the safest route is to identify the base first and then match the wording to the correct percent template.",
)
scaffold = ExplainerScaffold(
concept="Percent problems are built around a base amount, a compared amount, and a rate per hundred.",
ask="Decide which quantity is the whole/base, which quantity is the part or changed amount, and whether the question is asking for a percent, a value, or a new total.",
target="Translate the wording into the correct percent relationship before doing any arithmetic.",
answer_hidden=True,
solution_path_type=subtype,
)
result.teaching_points = [
"Percent means per hundred, so it should usually be converted to a decimal or fraction before setting up the relationship.",
"Most percent questions reduce to one of a small number of templates, so identifying the template matters more than rushing into calculation.",
"The biggest source of error is choosing the wrong base quantity.",
]
result.givens = [
"A percent, base, part, or changed amount is implied by the wording.",
]
result.relationships = [
"Percent relationships depend on correctly matching part, whole, and rate.",
]
result.needed_concepts = [
"base vs part",
"percent as a decimal or fraction",
"choosing the correct percent template",
]
result.trap_notes = [
"Choosing the wrong base quantity.",
"Using 40 instead of 0.40.",
"Confusing a basic percent-of problem with a percent-change problem.",
]
result.strategy_hint = "Start by asking: percent of what?"
if subtype == "basic_percent":
scaffold.setup_actions = [
"Label the known quantities as part, whole, and percent.",
"Convert the percent to a decimal or fraction.",
"Match the statement to the relationship: part = percent × whole.",
]
scaffold.intermediate_steps = [
"If the whole is unknown, assign it a variable.",
"Substitute the known values into the relationship.",
"Solve only after the structure is correct.",
]
scaffold.first_move = "Start by identifying the whole and the part."
scaffold.next_hint = "Once those roles are clear, write one equation connecting part, percent, and whole."
scaffold.variables_to_define = [
"Let x represent the unknown quantity if either the part or whole is missing.",
]
scaffold.equations_to_form = [
"part = percent × whole",
]
scaffold.key_operations = [
"identify the base",
"convert percent to decimal",
"build one equation",
]
scaffold.hint_ladder = [
"Which quantity is the whole?",
"What is the percent as a decimal?",
"Can you write part = percent × whole?",
]
elif subtype == "percent_of_percent":
scaffold.setup_actions = [
"Identify the comparison being made.",
"Place the compared quantity over the base quantity.",
"Convert the resulting fraction to a percent.",
]
scaffold.intermediate_steps = [
"Make sure the denominator is the reference/base amount.",
"Simplify the fraction if helpful.",
"Only convert to percent at the end.",
]
scaffold.first_move = "Ask: percent of what?"
scaffold.next_hint = "Use the base quantity as the denominator in the fraction before converting."
scaffold.equations_to_form = [
"percent = (part / whole) × 100",
]
scaffold.key_operations = [
"form the fraction",
"use the base as denominator",
"convert to percent",
]
scaffold.hint_ladder = [
"What is the reference amount?",
"Which number belongs in the denominator?",
"Multiply by 100 only after the fraction is correct.",
]
elif subtype == "percent_change":
scaffold.setup_actions = [
"Identify the original value and the new value.",
"Find the amount of change first.",
"Use the original value as the base in the percent-change formula.",
]
scaffold.intermediate_steps = [
"Compute change = new − original.",
"Place that change over the original value.",
"Convert the result to a percent.",
]
scaffold.first_move = "Find the amount of increase or decrease before thinking about the percent."
scaffold.next_hint = "After that, divide by the original amount, not the new amount."
scaffold.equations_to_form = [
"percent change = (new − original) / original × 100",
]
scaffold.key_operations = [
"find the change",
"divide by the original",
"convert to percent",
]
scaffold.hint_ladder = [
"Which value is original?",
"What is the amount of change?",
"Which quantity belongs in the denominator?",
]
elif subtype == "discount":
scaffold.setup_actions = [
"Identify the original price and the discount rate.",
"Find the discount amount from the original price.",
"Subtract the discount from the original price if the question asks for the sale price.",
]
scaffold.intermediate_steps = [
"Treat the listed price as the base.",
"Compute the discount amount separately from the final price.",
"Check whether the question asks for discount amount or discounted price.",
]
scaffold.first_move = "Use the original price as the percent base."
scaffold.next_hint = "Find the discount amount first, then decide whether to stop or subtract."
scaffold.equations_to_form = [
"discount = rate × original price",
"sale price = original price − discount",
]
scaffold.key_operations = [
"identify the original price",
"find discount amount",
"subtract if needed",
]
scaffold.hint_ladder = [
"What is the original price?",
"What percent of that price is the discount?",
"Does the question want the discount or the final price?",
]
elif subtype == "interest":
scaffold.setup_actions = [
"Identify principal, rate, and time.",
"Determine whether the question is simple interest or compound interest.",
"Set up the matching formula structure.",
]
scaffold.intermediate_steps = [
"For simple interest, keep the principal fixed.",
"For compound interest, recognize that the base changes from period to period.",
"Check whether the question asks for interest earned or final amount.",
]
scaffold.first_move = "Work out whether the interest is simple or compound."
scaffold.next_hint = "Then identify which quantity stays fixed and which quantity grows."
scaffold.key_operations = [
"identify principal, rate, and time",
"match simple vs compound",
"check whether the target is interest or total amount",
]
scaffold.hint_ladder = [
"Is the base changing each period?",
"Which quantity is the principal?",
"Does the question want interest earned or the total balance?",
]
elif subtype == "tax_tip":
scaffold.setup_actions = [
"Identify the pre-tax or pre-tip amount.",
"Use that original amount as the base.",
"Compute the tax or tip amount before adding if a total is required.",
]
scaffold.intermediate_steps = [
"Separate the added charge from the final amount.",
"Check whether multiple percentages are applied independently or sequentially.",
"Make sure the question wants the fee amount or the full total.",
]
scaffold.first_move = "Use the original listed amount as the base unless the wording clearly says otherwise."
scaffold.next_hint = "Find the added percent amount first, then combine only if the question asks for the total."
scaffold.equations_to_form = [
"added amount = rate × base amount",
"total = base amount + added amount",
]
scaffold.key_operations = [
"identify the original amount",
"find the added charge",
"add only if the question asks for the total",
]
scaffold.hint_ladder = [
"What is the amount before tax or tip?",
"How much is the added percent of that base?",
"Does the question stop at the fee or ask for the total bill?",
]
else:
scaffold.setup_actions = [
"Identify the base quantity.",
"Identify the compared quantity or changed amount.",
"Match the wording to a standard percent relationship.",
]
scaffold.intermediate_steps = [
"Convert the percent appropriately.",
"Build one clear relationship before solving.",
"Check whether the question asks for a value, a rate, or a final amount.",
]
scaffold.first_move = "Work out what the percent is being taken of."
scaffold.next_hint = "Once the base quantity is clear, write the relationship before calculating."
scaffold.key_operations = [
"identify the base",
"convert the percent",
"match the correct template",
]
scaffold.hint_ladder = [
"What quantity is the base?",
"What role does the percent play here?",
"Which standard percent relationship matches this wording?",
]
result.scaffold = scaffold
result.meta = {
"intent": "explain_question",
"bridge_ready": True,
"hint_style": "step_ready",
"subtype": subtype,
}
return result |