11 Commits

181 changed files with 83014 additions and 2676 deletions

View File

@ -20,6 +20,8 @@ import { TargetedPractice } from "./pages/student/targeted-practice/page";
import { Drills } from "./pages/student/drills/page";
import { HardTestModules } from "./pages/student/hard-test-modules/page";
import { Analytics } from "./pages/student/Analytics";
import { QuestMap } from "./pages/student/QuestMap";
import ErrorPage from "./pages/ErrorPage";
function App() {
const router = createBrowserRouter([
@ -58,6 +60,10 @@ function App() {
path: "analytics",
element: <Analytics />,
},
{
path: "quests",
element: <QuestMap />,
},
{
path: "practice/:sheetId",
element: <Pretest />,

View File

@ -0,0 +1,750 @@
import { useState, useEffect, useRef } from "react";
import type { QuestNode, ClaimedRewardResponse } from "../types/quest";
// ─── Styles ───────────────────────────────────────────────────────────────────
const S = `
@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@700;900&family=Nunito:wght@800;900&display=swap');
/* ══ FULL SCREEN OVERLAY ══ */
.com-overlay {
position:fixed; inset:0; z-index:80;
display:flex; flex-direction:column;
align-items:center; justify-content:center;
overflow:hidden;
}
/* ── Sky/sea background that animates in ── */
.com-bg {
position:absolute; inset:0;
background:
radial-gradient(ellipse 80% 60% at 50% 80%, rgba(0,60,120,0.9) 0%, transparent 70%),
radial-gradient(ellipse 60% 40% at 50% 20%, rgba(80,0,160,0.7) 0%, transparent 60%),
linear-gradient(180deg, #050010 0%, #0a0520 40%, #020818 100%);
animation: comBgIn 0.5s ease both;
}
@keyframes comBgIn {
from{ opacity:0; } to{ opacity:1; }
}
/* ── Stars in background ── */
.com-star {
position:absolute; border-radius:50%;
background:white; pointer-events:none;
animation:comStarTwinkle var(--sdur) ease-in-out infinite;
animation-delay:var(--sdelay);
}
@keyframes comStarTwinkle {
0%,100%{ opacity:0.3; transform:scale(1); }
50% { opacity:1; transform:scale(1.4); }
}
/* ── Gold radial burst (appears on open) ── */
.com-burst {
position:absolute; inset:0;
display:flex; align-items:center; justify-content:center;
pointer-events:none; z-index:2;
}
.com-burst-ring {
position:absolute; border-radius:50%;
border:3px solid rgba(251,191,36,0.6);
animation: comBurstRing var(--brdur) ease-out forwards;
animation-delay: var(--brdelay);
opacity:0;
}
@keyframes comBurstRing {
0% { opacity:0.9; transform:scale(0.1); }
100%{ opacity:0; transform:scale(var(--brs)); }
}
/* ── Ray beams (crepuscular rays) ── */
.com-rays {
position:absolute; inset:0;
display:flex; align-items:center; justify-content:center;
pointer-events:none; z-index:1;
}
.com-ray {
position:absolute;
width:3px;
height:55vh;
border-radius:100px;
background:linear-gradient(180deg,rgba(251,191,36,0.5) 0%,transparent 100%);
transform-origin:50% 100%;
bottom:50%;
left:calc(50% - 1.5px);
transform:rotate(var(--angle)) scaleY(0);
animation:comRayIn 0.6s ease-out forwards;
animation-delay:var(--raydelay);
}
@keyframes comRayIn {
0% { transform:rotate(var(--angle)) scaleY(0); opacity:0; }
40% { opacity:0.8; }
100%{ transform:rotate(var(--angle)) scaleY(1); opacity:0.15; }
}
/* ── Particle explosion ── */
.com-particle {
position:absolute; border-radius:50%;
pointer-events:none; z-index:4;
animation:comParticleOut var(--pdur) cubic-bezier(0.25,0.8,0.35,1) forwards;
animation-delay:var(--pdelay);
opacity:0;
}
@keyframes comParticleOut {
0% { opacity:1; transform:translate(0,0) scale(1) rotate(0deg); }
80% { opacity:0.7; }
100%{ opacity:0; transform:translate(var(--ptx),var(--pty)) scale(0.2) rotate(var(--prot)); }
}
/* ── Coin emojis bursting ── */
.com-coin {
position:absolute;
font-size:var(--csize);
pointer-events:none; z-index:4;
animation:comCoinOut var(--cdur) cubic-bezier(0.2,0.9,0.3,1) forwards;
animation-delay:var(--cdelay);
opacity:0;
}
@keyframes comCoinOut {
0% { opacity:0; transform:translate(0,0) rotate(0deg) scale(0.3); }
12% { opacity:1; }
100%{ opacity:0; transform:translate(var(--ctx),var(--cty)) rotate(var(--crot)) scale(1.1); }
}
/* ── Floating sparkles (stay on screen) ── */
.com-sparkle {
position:absolute; pointer-events:none; z-index:3;
font-size:var(--spsize);
animation:comSparkleFloat var(--spdur) ease-in-out infinite;
animation-delay:var(--spdelay);
opacity:0.7;
}
@keyframes comSparkleFloat {
0%,100%{ transform:translateY(0) rotate(0deg) scale(1); opacity:0.6; }
50% { transform:translateY(-18px) rotate(180deg) scale(1.2); opacity:1; }
}
/* ── XP number that flies up from chest ── */
.com-xp-blast {
position:absolute; pointer-events:none; z-index:5;
top:50%; left:50%;
font-family:'Cinzel',serif;
font-size:2.6rem; font-weight:900;
color:#fbbf24;
text-shadow:0 0 30px rgba(251,191,36,1),0 0 60px rgba(251,191,36,0.7),0 0 100px rgba(251,191,36,0.3);
white-space:nowrap;
animation:comXPBlast 2s cubic-bezier(0.2,0.8,0.3,1) forwards;
}
@keyframes comXPBlast {
0% { opacity:0; transform:translate(-50%,-40%) scale(0.4); filter:blur(4px); }
15% { opacity:1; transform:translate(-50%,-60%) scale(1.3); filter:blur(0); }
60% { opacity:1; transform:translate(-50%,-90%) scale(1); }
100%{ opacity:0; transform:translate(-50%,-130%) scale(0.8); }
}
/* ── Main card ── */
.com-card {
position:relative; z-index:6;
width:calc(100% - 2.5rem); max-width:340px;
border-radius:28px; overflow:hidden;
display:flex; flex-direction:column; align-items:center;
padding:0;
box-shadow:0 0 80px rgba(251,191,36,0.2), 0 24px 64px rgba(0,0,0,0.7);
animation:comCardIn 0.5s cubic-bezier(0.34,1.56,0.64,1) both;
animation-delay:0.1s;
}
@keyframes comCardIn {
from{ opacity:0; transform:scale(0.8) translateY(24px); }
to { opacity:1; transform:scale(1) translateY(0); }
}
/* Gold shimmer top border */
.com-card::before {
content:''; position:absolute; top:0; left:0; right:0; height:2px; z-index:1;
background:linear-gradient(90deg,transparent 0%,#f59e0b 30%,#fbbf24 50%,#f59e0b 70%,transparent 100%);
background-size:200% 100%;
animation:comShimmer 2s linear infinite;
}
@keyframes comShimmer {
0% { background-position:200% 0; }
100%{ background-position:-200% 0; }
}
/* Card inner bg */
.com-card-inner {
width:100%; padding:1.75rem 1.6rem 1.6rem;
background:linear-gradient(160deg,#12083a 0%,#0c0525 60%,#090320 100%);
border:1.5px solid rgba(251,191,36,0.25);
border-radius:28px;
display:flex; flex-direction:column; align-items:center; gap:0;
}
/* ── Phase label ── */
.com-label {
font-family:'Cinzel',serif;
font-size:0.62rem; font-weight:700; letter-spacing:0.2em;
text-transform:uppercase; color:rgba(251,191,36,0.55);
margin-bottom:1.2rem; text-align:center;
}
/* ── Chest area ── */
.com-chest-area {
position:relative; width:140px; height:140px;
display:flex; align-items:center; justify-content:center;
margin-bottom:1.25rem; cursor:pointer;
}
/* Glow platform beneath chest */
.com-glow-pad {
position:absolute; bottom:6px; left:50%;
transform:translateX(-50%);
width:100px; height:24px; border-radius:50%;
background:radial-gradient(ellipse at center,rgba(251,191,36,0.45) 0%,transparent 70%);
animation:comGlowPad 1.8s ease-in-out infinite;
filter:blur(4px);
}
@keyframes comGlowPad {
0%,100%{ transform:translateX(-50%) scaleX(1); opacity:0.7; }
50% { transform:translateX(-50%) scaleX(1.2); opacity:1; }
}
/* Orbit ring */
.com-orbit {
position:absolute; inset:8px; border-radius:50%;
border:1.5px dashed rgba(251,191,36,0.2);
animation:comOrbit 8s linear infinite;
}
@keyframes comOrbit { from{transform:rotate(0deg);} to{transform:rotate(360deg);} }
.com-orbit-dot {
position:absolute; top:-5px; left:50%; transform:translateX(-50%);
width:8px; height:8px; border-radius:50%;
background:#fbbf24; box-shadow:0 0 10px #fbbf24;
}
/* The chest emoji */
.com-chest {
font-size:5.5rem; position:relative; z-index:2;
filter:drop-shadow(0 8px 20px rgba(251,191,36,0.45));
transition:filter 0.2s;
}
.com-chest.idle {
animation:comChestIdle 3s ease-in-out infinite;
}
@keyframes comChestIdle {
0%,100%{ transform:translateY(0) rotate(-2deg); }
50% { transform:translateY(-6px) rotate(2deg); }
}
.com-chest.shake {
animation:comChestShake 0.55s cubic-bezier(0.36,0.07,0.19,0.97) both;
}
@keyframes comChestShake {
0%,100%{ transform:rotate(0deg) scale(1); }
10% { transform:rotate(-14deg) scale(1.06); }
25% { transform:rotate(14deg) scale(1.1); }
40% { transform:rotate(-10deg) scale(1.07); }
55% { transform:rotate(10deg) scale(1.12); }
70% { transform:rotate(-6deg) scale(1.06); }
85% { transform:rotate(6deg) scale(1.04); }
}
.com-chest.opening {
animation:comChestOpen 0.5s cubic-bezier(0.34,1.56,0.64,1) both;
}
@keyframes comChestOpen {
0% { transform:scale(0.7); filter:brightness(0.4) drop-shadow(0 8px 20px rgba(251,191,36,0.3)); }
50% { transform:scale(1.25); filter:brightness(1.8) drop-shadow(0 0 50px rgba(251,191,36,1)); }
100%{ transform:scale(1); filter:brightness(1) drop-shadow(0 8px 30px rgba(251,191,36,0.6)); }
}
/* ── Tap prompt ── */
.com-tap-title {
font-family:'Cinzel',serif;
font-size:1.2rem; font-weight:900; color:white;
text-align:center; margin-bottom:0.3rem;
animation:comPulse 1.8s ease-in-out infinite;
}
@keyframes comPulse {
0%,100%{ opacity:1; transform:scale(1); }
50% { opacity:0.65; transform:scale(0.97); }
}
.com-tap-sub {
font-family:'Nunito',sans-serif;
font-size:0.75rem; font-weight:800;
color:rgba(255,255,255,0.35); text-align:center; margin-bottom:1.5rem;
letter-spacing:0.06em;
}
/* ── Shaking text ── */
.com-shake-text {
font-family:'Cinzel',serif;
font-size:1.1rem; font-weight:900; color:#fbbf24;
text-align:center; margin-bottom:0.3rem;
animation:comShakeText 0.3s ease-in-out infinite alternate;
}
@keyframes comShakeText {
from{ transform:translateX(-3px); }
to { transform:translateX(3px); }
}
.com-shake-dots {
font-size:1.4rem; text-align:center; margin-bottom:1.5rem;
animation:comShakeText 0.25s ease-in-out infinite alternate;
}
/* ── Reward rows ── */
.com-rewards-title {
font-family:'Cinzel',serif;
font-size:0.65rem; font-weight:700; letter-spacing:0.18em;
text-transform:uppercase; color:rgba(251,191,36,0.5);
text-align:center; margin-bottom:0.85rem;
}
.com-rewards { display:flex; flex-direction:column; gap:0.55rem; width:100%; margin-bottom:1.1rem; }
.com-reward-row {
display:flex; align-items:center; gap:0.85rem;
padding:0.8rem 1rem;
background:rgba(255,255,255,0.04);
border:1px solid rgba(251,191,36,0.18);
border-radius:16px;
animation:comRowIn 0.5s cubic-bezier(0.34,1.56,0.64,1) both;
}
@keyframes comRowIn {
from{ opacity:0; transform:translateY(18px) scale(0.88); }
to { opacity:1; transform:translateY(0) scale(1); }
}
.com-reward-icon { font-size:1.5rem; flex-shrink:0; filter:drop-shadow(0 2px 8px rgba(251,191,36,0.5)); }
.com-reward-lbl {
font-family:'Cinzel',serif;
font-size:0.65rem; font-weight:700; letter-spacing:0.1em; text-transform:uppercase;
color:rgba(255,255,255,0.4); margin-bottom:0.12rem;
}
.com-reward-val {
font-family:'Nunito',sans-serif;
font-size:1.05rem; font-weight:900;
color:#fbbf24;
text-shadow:0 0 16px rgba(251,191,36,0.6);
}
/* Special XP row highlight */
.com-reward-row.xp-row {
border-color:rgba(251,191,36,0.35);
background:rgba(251,191,36,0.06);
}
/* Loading state inside reward area */
.com-rewards-loading {
font-family:'Cinzel',serif;
font-size:0.72rem; font-weight:700; color:rgba(251,191,36,0.4);
text-align:center; padding:1rem 0; letter-spacing:0.1em;
animation:comPulse 1.2s ease-in-out infinite;
}
/* ── CTA button ── */
.com-cta {
width:100%; padding:1rem;
background:linear-gradient(135deg,#fbbf24,#f59e0b);
border:none; border-radius:16px; cursor:pointer;
font-family:'Cinzel',serif;
font-size:1rem; font-weight:900; color:#1a0800;
letter-spacing:0.05em;
box-shadow:0 5px 0 #b45309, 0 8px 24px rgba(251,191,36,0.4);
transition:all 0.12s ease;
animation:comRowIn 0.5s cubic-bezier(0.34,1.56,0.64,1) both;
}
.com-cta:hover { transform:translateY(-3px); box-shadow:0 8px 0 #b45309, 0 14px 32px rgba(251,191,36,0.5); }
.com-cta:active { transform:translateY(2px); box-shadow:0 3px 0 #b45309; }
/* ── Skip hint ── */
.com-skip {
position:absolute; bottom:1.5rem;
font-family:'Nunito',sans-serif;
font-size:0.65rem; font-weight:700;
color:rgba(255,255,255,0.2); letter-spacing:0.1em;
text-transform:uppercase; cursor:pointer; z-index:7;
transition:color 0.2s;
}
.com-skip:hover { color:rgba(255,255,255,0.5); }
`;
// ─── Config ───────────────────────────────────────────────────────────────────
const PARTICLE_COLORS = [
"#fbbf24",
"#f59e0b",
"#ef4444",
"#ec4899",
"#a855f7",
"#6366f1",
"#22d3ee",
"#4ade80",
"#fb923c",
];
const COIN_EMOJIS = ["🪙", "💰", "✨", "⭐", "💎", "🌟", "💫", "🏅"];
const SPARKLE_EMOJIS = ["✨", "⭐", "💫", "🌟"];
const RAYS = Array.from({ length: 12 }, (_, i) => ({
id: i,
angle: `${(i / 12) * 360}deg`,
delay: `${i * 0.04}s`,
}));
const BURST_RINGS = [
{ id: 0, size: "3", dur: "0.7s", delay: "0s" },
{ id: 1, size: "5", dur: "0.9s", delay: "0.1s" },
{ id: 2, size: "8", dur: "1.1s", delay: "0.2s" },
{ id: 3, size: "12", dur: "1.4s", delay: "0.3s" },
];
const STARS = Array.from({ length: 40 }, (_, i) => ({
id: i,
w: 1 + ((i * 7) % 3),
top: `${(i * 17 + 3) % 95}%`,
left: `${(i * 23 + 11) % 97}%`,
dur: `${2 + ((i * 3) % 4)}s`,
delay: `${(i * 7) % 3}s`,
}));
const SPARKLES = Array.from({ length: 8 }, (_, i) => ({
id: i,
emoji: SPARKLE_EMOJIS[i % 4],
size: `${0.9 + (i % 3) * 0.35}rem`,
top: `${10 + ((i * 12) % 75)}%`,
left: `${5 + ((i * 14) % 85)}%`,
dur: `${2 + (i % 3) * 1.2}s`,
delay: `${i * 0.3}s`,
}));
type Phase = "idle" | "shaking" | "opening" | "revealed";
interface Props {
node: QuestNode;
claimResult: ClaimedRewardResponse | null;
onClose: () => void;
}
export const ChestOpenModal = ({ node, claimResult, onClose }: Props) => {
const [phase, setPhase] = useState<Phase>("idle");
const [showXP, setShowXP] = useState(false);
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
// Stable particle arrays computed once per mount
const particles = useRef(
Array.from({ length: 55 }, (_, i) => ({
id: i,
color: PARTICLE_COLORS[i % PARTICLE_COLORS.length],
w: 3 + (i % 3) * 4,
tx: ((i % 2 === 0 ? 1 : -1) * (40 + i * 7)) % 200,
ty: -(30 + ((i * 11) % 190)),
rot: ((i * 23) % 720) - 360,
dur: `${0.7 + ((i * 7) % 10) / 10}s`,
delay: `${((i * 3) % 8) / 30}s`,
})),
).current;
const coins = useRef(
Array.from({ length: 18 }, (_, i) => ({
id: i,
emoji: COIN_EMOJIS[i % COIN_EMOJIS.length],
size: `${1 + (i % 3) * 0.45}rem`,
tx: (i % 2 === 0 ? 1 : -1) * (30 + ((i * 9) % 180)),
ty: -(40 + ((i * 13) % 200)),
rot: ((i * 31) % 540) - 270,
dur: `${0.75 + ((i * 7) % 8) / 10}s`,
delay: `${((i * 5) % 10) / 30}s`,
})),
).current;
const tap = () => {
if (phase !== "idle") return;
setPhase("shaking");
timerRef.current = setTimeout(() => {
setPhase("opening");
setShowXP(true);
timerRef.current = setTimeout(() => {
setShowXP(false);
setPhase("revealed");
}, 1800);
}, 650);
};
useEffect(
() => () => {
if (timerRef.current) clearTimeout(timerRef.current);
},
[],
);
// ── Build reward rows from ClaimedRewardResponse ──────────────────────────
// claimResult may be null while the API call is in flight; we show a loading
// state in that case rather than crashing or showing stale data.
const xpAwarded = claimResult?.xp_awarded ?? 0;
// Defensively coerce to arrays — the API may return null, a single object,
// or omit these fields entirely rather than returning an empty array.
const titlesAwarded = Array.isArray(claimResult?.title_unlocked)
? claimResult!.title_unlocked
: claimResult?.title_unlocked
? [claimResult.title_unlocked]
: [];
const itemsAwarded = Array.isArray(claimResult?.items_awarded)
? claimResult!.items_awarded
: claimResult?.items_awarded
? [claimResult.items_awarded]
: [];
const rewards = claimResult
? [
// XP row — always present
{
key: "xp",
cls: "xp-row",
icon: "⚡",
lbl: "XP Gained",
val: `+${xpAwarded} XP`,
delay: "0.05s",
},
// One row per unlocked title (usually 0 or 1)
...titlesAwarded.map((t, i) => ({
key: `title-${t.id}`,
cls: "",
icon: "🏴‍☠️",
lbl: "Crew Title",
val: t.name,
delay: `${0.1 + i * 0.1}s`,
})),
// One row per awarded item
...itemsAwarded.map((inv, i) => ({
key: `item-${inv.id}`,
cls: "",
icon: "🎁",
lbl: inv.item.type ?? "Item",
val: inv.item.name,
delay: `${0.1 + (titlesAwarded.length + i) * 0.1}s`,
})),
]
: [];
const chestClass =
phase === "idle"
? "idle"
: phase === "shaking"
? "shake"
: phase === "opening"
? "opening"
: "";
const chestEmoji = phase === "opening" || phase === "revealed" ? "📬" : "📦";
return (
<div className="com-overlay" onClick={phase === "idle" ? tap : undefined}>
<style>{S}</style>
{/* Background */}
<div className="com-bg" />
{/* Stars */}
{STARS.map((s) => (
<div
key={s.id}
className="com-star"
style={
{
width: s.w,
height: s.w,
top: s.top,
left: s.left,
"--sdur": s.dur,
"--sdelay": s.delay,
} as React.CSSProperties
}
/>
))}
{/* Crepuscular rays */}
{(phase === "opening" || phase === "revealed") && (
<div className="com-rays">
{RAYS.map((r) => (
<div
key={r.id}
className="com-ray"
style={
{
"--angle": r.angle,
"--raydelay": r.delay,
} as React.CSSProperties
}
/>
))}
</div>
)}
{/* Burst rings */}
{(phase === "opening" || phase === "revealed") && (
<div className="com-burst">
{BURST_RINGS.map((r) => (
<div
key={r.id}
className="com-burst-ring"
style={
{
width: "100px",
height: "100px",
"--brs": r.size,
"--brdur": r.dur,
"--brdelay": r.delay,
} as React.CSSProperties
}
/>
))}
</div>
)}
{/* Particle explosion */}
{(phase === "opening" || phase === "revealed") && (
<>
{particles.map((p) => (
<div
key={p.id}
className="com-particle"
style={
{
width: p.w,
height: p.w,
background: p.color,
top: "50%",
left: "50%",
"--ptx": `${p.tx}px`,
"--pty": `${p.ty}px`,
"--prot": `${p.rot}deg`,
"--pdur": p.dur,
"--pdelay": p.delay,
} as React.CSSProperties
}
/>
))}
{coins.map((c) => (
<div
key={c.id}
className="com-coin"
style={
{
top: "50%",
left: "50%",
"--csize": c.size,
"--ctx": `${c.tx}px`,
"--cty": `${c.ty}px`,
"--crot": `${c.rot}deg`,
"--cdur": c.dur,
"--cdelay": c.delay,
} as React.CSSProperties
}
>
{c.emoji}
</div>
))}
</>
)}
{/* Floating sparkles in revealed state */}
{phase === "revealed" &&
SPARKLES.map((sp) => (
<div
key={sp.id}
className="com-sparkle"
style={
{
top: sp.top,
left: sp.left,
"--spsize": sp.size,
"--spdur": sp.dur,
"--spdelay": sp.delay,
} as React.CSSProperties
}
>
{sp.emoji}
</div>
))}
{/* XP blast — uses xp_awarded from claimResult */}
{showXP && (
<div className="com-xp-blast">
{xpAwarded > 0 ? `+${xpAwarded} XP` : "✨"}
</div>
)}
{/* Card */}
<div className="com-card" onClick={(e) => e.stopPropagation()}>
<div className="com-card-inner">
<p className="com-label">
{phase === "revealed" ? "⚓ Treasure Claimed" : "📦 Treasure Chest"}
</p>
{/* Chest */}
<div
className="com-chest-area"
onClick={phase === "idle" ? tap : undefined}
style={{ cursor: phase === "idle" ? "pointer" : "default" }}
>
{phase !== "revealed" && <div className="com-glow-pad" />}
{phase !== "revealed" && (
<div className="com-orbit">
<div className="com-orbit-dot" />
</div>
)}
<span className={`com-chest ${chestClass}`}>{chestEmoji}</span>
</div>
{/* Phase content */}
{phase === "idle" && (
<>
<p className="com-tap-title">Tap to Open!</p>
<p className="com-tap-sub">YOUR HARD WORK HAS PAID OFF, PIRATE</p>
</>
)}
{phase === "shaking" && (
<>
<p className="com-shake-text">The chest stirs...</p>
<p className="com-shake-dots"> </p>
</>
)}
{phase === "revealed" && (
<>
<p className="com-rewards-title"> Spoils of Victory</p>
<div className="com-rewards">
{/* claimResult not yet available — API still in flight */}
{!claimResult && (
<p className="com-rewards-loading">
Counting your spoils...
</p>
)}
{rewards.map((r) => (
<div
key={r.key}
className={`com-reward-row ${r.cls}`}
style={{ animationDelay: r.delay }}
>
<span className="com-reward-icon">{r.icon}</span>
<div>
<p className="com-reward-lbl">{r.lbl}</p>
<p className="com-reward-val">{r.val}</p>
</div>
</div>
))}
</div>
<button
className="com-cta"
style={{ animationDelay: `${rewards.length * 0.1}s` }}
onClick={onClose}
>
Set Sail
</button>
</>
)}
</div>
</div>
{/* Skip link */}
{phase === "revealed" && (
<p className="com-skip" onClick={onClose}>
tap anywhere to continue
</p>
)}
</div>
);
};

View File

@ -0,0 +1,199 @@
// lessonRegistry.tsx
import { lazy, type ComponentType } from "react";
// lessonTypes.ts
export type LessonId =
// ---- EBRW ----
| "ebrw-main-idea"
| "ebrw-explicit-meaning"
| "ebrw-inferences"
| "ebrw-graphic-displays"
| "ebrw-craft-structure"
| "ebrw-vocab-precise"
| "ebrw-vocab-meaning"
| "ebrw-expression-ideas"
| "ebrw-transitions"
| "ebrw-commas"
| "ebrw-semicolons-colons"
| "ebrw-dashes-apostrophes"
| "ebrw-subject-verb"
| "ebrw-pronouns"
| "ebrw-verbs"
| "ebrw-sentence-structure"
// ---- MATH ----
| "alg-linear-eq-1var"
| "alg-linear-eq-2var"
| "alg-linear-functions"
| "alg-systems"
| "alg-linear-inequalities"
| "adv-equivalent-expr"
| "adv-nonlinear-eq"
| "adv-systems-2var"
| "adv-nonlinear-func"
| "data-ratios-rates"
| "data-percentages"
| "data-one-var"
| "data-two-var"
| "data-probability"
| "data-sample-stats"
| "data-eval-claims"
| "geom-area-volume"
| "geom-lines-angles"
| "geom-right-tri-trig"
| "geom-circles";
// ---- EBRW ----
const EBRWMainIdea = lazy(
() => import("../pages/student/lessons/EBRWMainIdeaLesson"),
);
const EBRWExplicitMeaning = lazy(
() => import("../pages/student/lessons/EBRWExplicitMeaningLesson"),
);
const EBRWInferences = lazy(
() => import("../pages/student/lessons/EBRWInferencesLesson"),
);
const EBRWGraphicDisplays = lazy(
() => import("../pages/student/lessons/EBRWGraphicDisplaysLesson"),
);
const EBRWCraftStructure = lazy(
() => import("../pages/student/lessons/EBRWCraftStructureLesson"),
);
const EBRWVocabPrecise = lazy(
() => import("../pages/student/lessons/EBRWVocabPreciseLesson"),
);
const EBRWVocabMeaning = lazy(
() => import("../pages/student/lessons/EBRWVocabMeaningLesson"),
);
const EBRWExpressionIdeas = lazy(
() => import("../pages/student/lessons/EBRWExpressionIdeasLesson"),
);
const EBRWTransitions = lazy(
() => import("../pages/student/lessons/EBRWTransitionsLesson"),
);
const EBRWCommas = lazy(
() => import("../pages/student/lessons/EBRWCommasLesson"),
);
const EBRWSemicolonsColons = lazy(
() => import("../pages/student/lessons/EBRWSemicolonsColonsLesson"),
);
const EBRWDashesApostrophes = lazy(
() => import("../pages/student/lessons/EBRWDashesApostrophesLesson"),
);
const EBRWSubjectVerb = lazy(
() => import("../pages/student/lessons/EBRWSubjectVerbLesson"),
);
const EBRWPronouns = lazy(
() => import("../pages/student/lessons/EBRWPronounsLesson"),
);
const EBRWVerbs = lazy(
() => import("../pages/student/lessons/EBRWVerbsLesson"),
);
const EBRWSentenceStructure = lazy(
() => import("../pages/student/lessons/EBRWSentenceStructureLesson"),
);
// ---- MATH ----
const AlgLinearEq1Var = lazy(
() => import("../pages/student/lessons/LinearEq1VarLesson"),
);
const AlgLinearEq2Var = lazy(
() => import("../pages/student/lessons/LinearEq2VarLesson"),
);
const AlgLinearFunctions = lazy(
() => import("../pages/student/lessons/LinearFunctionsLesson"),
);
const AlgSystems = lazy(
() => import("../pages/student/lessons/SystemsEquationsLesson"),
);
const AlgLinearInequalities = lazy(
() => import("../pages/student/lessons/LinearInequalitiesLesson"),
);
const AdvEquivalentExpr = lazy(
() => import("../pages/student/lessons/EquivalentExpressionsLesson"),
);
const AdvNonlinearEq = lazy(
() => import("../pages/student/lessons/NonlinearEq1VarLesson"),
);
const AdvSystems2Var = lazy(
() => import("../pages/student/lessons/SystemsEq2VarLesson"),
);
const AdvNonlinearFunc = lazy(
() => import("../pages/student/lessons/NonlinearFunctionsLesson"),
);
const DataRatiosRates = lazy(
() => import("../pages/student/lessons/RatiosRatesLesson"),
);
const DataPercentages = lazy(
() => import("../pages/student/lessons/PercentagesLesson"),
);
const DataOneVar = lazy(
() => import("../pages/student/lessons/OneVariableDataLesson"),
);
const DataTwoVar = lazy(
() => import("../pages/student/lessons/TwoVariableDataLesson"),
);
const DataProbability = lazy(
() => import("../pages/student/lessons/ProbabilityLesson"),
);
const DataSampleStats = lazy(
() => import("../pages/student/lessons/SampleStatsLesson"),
);
const DataEvalClaims = lazy(
() => import("../pages/student/lessons/EvalStatisticalClaimsLesson"),
);
const GeomAreaVolume = lazy(
() => import("../pages/student/lessons/AreaVolumeLesson"),
);
const GeomLinesAngles = lazy(
() => import("../pages/student/lessons/LinesAnglesLesson"),
);
const GeomRightTriTrig = lazy(
() => import("../pages/student/lessons/RightTrianglesTrigLesson"),
);
const GeomCircles = lazy(
() => import("../pages/student/lessons/CirclesLesson"),
);
// ---- Registry Map ----
export const LESSON_COMPONENT_MAP: Record<LessonId, ComponentType> = {
// EBRW
"ebrw-main-idea": EBRWMainIdea,
"ebrw-explicit-meaning": EBRWExplicitMeaning,
"ebrw-inferences": EBRWInferences,
"ebrw-graphic-displays": EBRWGraphicDisplays,
"ebrw-craft-structure": EBRWCraftStructure,
"ebrw-vocab-precise": EBRWVocabPrecise,
"ebrw-vocab-meaning": EBRWVocabMeaning,
"ebrw-expression-ideas": EBRWExpressionIdeas,
"ebrw-transitions": EBRWTransitions,
"ebrw-commas": EBRWCommas,
"ebrw-semicolons-colons": EBRWSemicolonsColons,
"ebrw-dashes-apostrophes": EBRWDashesApostrophes,
"ebrw-subject-verb": EBRWSubjectVerb,
"ebrw-pronouns": EBRWPronouns,
"ebrw-verbs": EBRWVerbs,
"ebrw-sentence-structure": EBRWSentenceStructure,
// MATH
"alg-linear-eq-1var": AlgLinearEq1Var,
"alg-linear-eq-2var": AlgLinearEq2Var,
"alg-linear-functions": AlgLinearFunctions,
"alg-systems": AlgSystems,
"alg-linear-inequalities": AlgLinearInequalities,
"adv-equivalent-expr": AdvEquivalentExpr,
"adv-nonlinear-eq": AdvNonlinearEq,
"adv-systems-2var": AdvSystems2Var,
"adv-nonlinear-func": AdvNonlinearFunc,
"data-ratios-rates": DataRatiosRates,
"data-percentages": DataPercentages,
"data-one-var": DataOneVar,
"data-two-var": DataTwoVar,
"data-probability": DataProbability,
"data-sample-stats": DataSampleStats,
"data-eval-claims": DataEvalClaims,
"geom-area-volume": GeomAreaVolume,
"geom-lines-angles": GeomLinesAngles,
"geom-right-tri-trig": GeomRightTriTrig,
"geom-circles": GeomCircles,
};

View File

@ -1,93 +0,0 @@
import { useEffect, useRef } from "react";
declare global {
interface Window {
GGBApplet: any;
}
}
interface GraphProps {
width?: string;
height?: string;
commands?: string[];
defaultZoom?: number;
}
export function Graph({
width = "w-full",
height = "h-30",
commands = [],
defaultZoom = 1,
}: GraphProps) {
const containerRef = useRef<HTMLDivElement>(null);
const appRef = useRef<any>(null);
useEffect(() => {
if (!(window as any).GGBApplet) {
console.error("GeoGebra library not loaded");
return;
}
const applet = new window.GGBApplet(
{
appName: "graphing",
width: 480,
height: 320,
scale: 1.4,
showToolBar: false,
showAlgebraInput: false,
showMenuBar: false,
showResetIcon: false,
enableRightClick: false,
enableLabelDrags: false,
enableShiftDragZoom: true,
showZoomButtons: true,
appletOnLoad(api: any) {
appRef.current = api;
api.setPerspective("G");
api.setMode(0);
api.setAxesVisible(true, true);
api.setGridVisible(true);
api.setCoordSystem(-5, 5, -5, 5);
commands.forEach((command, i) => {
const name = `f${i}`;
api.evalCommand(`${name}: ${command}`);
api.setFixed(name, true);
});
// Inside appletOnLoad:
},
},
true,
);
applet.inject("ggb-container");
}, [commands, defaultZoom]);
useEffect(() => {
const resize = () => {
if (!containerRef.current || !appRef.current) return;
appRef.current.setSize(
containerRef.current.offsetWidth,
containerRef.current.offsetHeight,
);
};
window.addEventListener("resize", resize);
resize(); // initial resize
return () => window.removeEventListener("resize", resize);
}, []);
return (
<div ref={containerRef} className="h-[480] w-[320]">
<div id="ggb-container" className="w-full h-full" />
</div>
);
}

View File

@ -1,634 +0,0 @@
import { useRef, useEffect, useState, useCallback, useMemo } from "react";
// ─── Types ────────────────────────────────────────────────────────────────────
export interface Equation {
/** A JS math expression in terms of x. e.g. "Math.sin(x)", "x**2 - 3" */
fn: string;
/** Hex or CSS color string */
color?: string;
/** Display label e.g. "y = x²" */
label?: string;
}
interface GraphPlotterProps {
equations: Equation[];
width?: number | string;
height?: number | string;
}
interface Intersection {
x: number;
y: number;
eqA: number;
eqB: number;
}
interface TooltipState {
screenX: number;
screenY: number;
mathX: number;
mathY: number;
eqA: number;
eqB: number;
}
// ─── Palette ──────────────────────────────────────────────────────────────────
const DEFAULT_COLORS = [
"#e05263", // crimson-rose
"#3b82f6", // blue
"#10b981", // emerald
"#f59e0b", // amber
"#a855f7", // violet
"#06b6d4", // cyan
"#f97316", // orange
];
// ─── Safe function evaluator ──────────────────────────────────────────────────
const buildFn = (expr: string): ((x: number) => number) => {
try {
// eslint-disable-next-line no-new-func
return new Function(
"x",
`"use strict"; try { return ${expr}; } catch(e) { return NaN; }`,
) as (x: number) => number;
} catch {
return () => NaN;
}
};
// ─── Intersection finder (bisection on sign changes) ─────────────────────────
const findIntersections = (
fns: Array<(x: number) => number>,
xMin: number,
xMax: number,
steps = 800,
): Intersection[] => {
const results: Intersection[] = [];
const dx = (xMax - xMin) / steps;
for (let a = 0; a < fns.length; a++) {
for (let b = a + 1; b < fns.length; b++) {
const diff = (x: number) => fns[a](x) - fns[b](x);
let prev = diff(xMin);
for (let i = 1; i <= steps; i++) {
const x1 = xMin + i * dx;
const cur = diff(x1);
if (isFinite(prev) && isFinite(cur) && prev * cur < 0) {
// Bisect
let lo = x1 - dx,
hi = x1;
for (let k = 0; k < 42; k++) {
const mid = (lo + hi) / 2;
const m = diff(mid);
if (Math.abs(m) < 1e-10) {
lo = hi = mid;
break;
}
if (m * diff(lo) < 0) hi = mid;
else lo = mid;
}
const rx = (lo + hi) / 2;
const ry = fns[a](rx);
if (isFinite(rx) && isFinite(ry)) {
// Dedupe
const dupe = results.some(
(p) => p.eqA === a && p.eqB === b && Math.abs(p.x - rx) < 1e-4,
);
if (!dupe) results.push({ x: rx, y: ry, eqA: a, eqB: b });
}
}
prev = cur;
}
}
}
return results;
};
// ─── Main Component ───────────────────────────────────────────────────────────
export const GraphPlotter = ({
equations,
width = "100%",
height = 480,
}: GraphPlotterProps) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
// Viewport state: origin in math coords + pixels-per-unit
const [viewport, setViewport] = useState({ cx: 0, cy: 0, scale: 60 });
const [canvasSize, setCanvasSize] = useState({ w: 600, h: 480 });
const [tooltip, setTooltip] = useState<TooltipState | null>(null);
const [activeIntersections, setActiveIntersections] = useState<
Intersection[]
>([]);
// Pan state
const isPanning = useRef(false);
const lastPointer = useRef({ x: 0, y: 0 });
const lastPinchDist = useRef<number | null>(null);
// Build compiled functions
const compiledFns = useMemo(
() => equations.map((eq) => buildFn(eq.fn)),
[equations],
);
// Math → screen
const toScreen = useCallback(
(mx: number, my: number, vp = viewport, cs = canvasSize) => ({
sx: cs.w / 2 + (mx - vp.cx) * vp.scale,
sy: cs.h / 2 - (my - vp.cy) * vp.scale,
}),
[viewport, canvasSize],
);
// Screen → math
const toMath = useCallback(
(sx: number, sy: number, vp = viewport, cs = canvasSize) => ({
mx: vp.cx + (sx - cs.w / 2) / vp.scale,
my: vp.cy - (sy - cs.h / 2) / vp.scale,
}),
[viewport, canvasSize],
);
// Resize observer
useEffect(() => {
const el = containerRef.current;
if (!el) return;
const ro = new ResizeObserver((entries) => {
for (const e of entries) {
const { width: w, height: h } = e.contentRect;
setCanvasSize({ w: Math.floor(w), h: Math.floor(h) });
}
});
ro.observe(el);
return () => ro.disconnect();
}, []);
// Compute intersections when fns or viewport changes
useEffect(() => {
if (compiledFns.length < 2) {
setActiveIntersections([]);
return;
}
const xMin = viewport.cx - canvasSize.w / (2 * viewport.scale);
const xMax = viewport.cx + canvasSize.w / (2 * viewport.scale);
const its = findIntersections(compiledFns, xMin, xMax);
setActiveIntersections(its);
}, [compiledFns, viewport, canvasSize]);
// ── Draw ──────────────────────────────────────────────────────────────────
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
const { w, h } = canvasSize;
canvas.width = w * devicePixelRatio;
canvas.height = h * devicePixelRatio;
canvas.style.width = `${w}px`;
canvas.style.height = `${h}px`;
ctx.scale(devicePixelRatio, devicePixelRatio);
const vp = viewport;
const { sx: ox, sy: oy } = toScreen(0, 0, vp, canvasSize);
// Background
ctx.fillStyle = "#fafaf9";
ctx.fillRect(0, 0, w, h);
// Grid
const drawGrid = (
unit: number,
alpha: number,
lineWidth: number,
textSize?: number,
) => {
ctx.strokeStyle = `rgba(180,180,175,${alpha})`;
ctx.lineWidth = lineWidth;
ctx.beginPath();
const xStart = Math.floor((0 - ox) / (unit * vp.scale)) - 1;
const xEnd = Math.ceil((w - ox) / (unit * vp.scale)) + 1;
for (let i = xStart; i <= xEnd; i++) {
const sx = ox + i * unit * vp.scale;
ctx.moveTo(sx, 0);
ctx.lineTo(sx, h);
}
const yStart = Math.floor((oy - h) / (unit * vp.scale)) - 1;
const yEnd = Math.ceil(oy / (unit * vp.scale)) + 1;
for (let j = yStart; j <= yEnd; j++) {
const sy = oy - j * unit * vp.scale;
ctx.moveTo(0, sy);
ctx.lineTo(w, sy);
}
ctx.stroke();
// Labels
if (textSize) {
ctx.fillStyle = "#a8a29e";
ctx.font = `${textSize}px ui-monospace, monospace`;
ctx.textAlign = "center";
ctx.textBaseline = "top";
for (let i = xStart; i <= xEnd; i++) {
if (i === 0) continue;
const sx = ox + i * unit * vp.scale;
const val = i * unit;
const label = Number.isInteger(val) ? val.toString() : val.toFixed(1);
ctx.fillText(label, sx, oy + 4);
}
ctx.textAlign = "right";
ctx.textBaseline = "middle";
for (let j = yStart; j <= yEnd; j++) {
if (j === 0) continue;
const sy = oy - j * unit * vp.scale;
const val = j * unit;
const label = Number.isInteger(val) ? val.toString() : val.toFixed(1);
ctx.fillText(label, ox - 6, sy);
}
}
};
// Adaptive grid unit
const rawUnit = 1;
const targetPixels = 50;
const exp = Math.floor(Math.log10(targetPixels / vp.scale));
const unit = rawUnit * Math.pow(10, exp);
const subUnit = unit / 5;
drawGrid(subUnit, 0.35, 0.5);
drawGrid(unit, 0.7, 0.8, 10);
// Axes
ctx.strokeStyle = "#57534e";
ctx.lineWidth = 1.5;
ctx.beginPath();
ctx.moveTo(0, oy);
ctx.lineTo(w, oy);
ctx.moveTo(ox, 0);
ctx.lineTo(ox, h);
ctx.stroke();
// Arrow heads
const arrow = (x: number, y: number, dir: "r" | "u") => {
ctx.fillStyle = "#57534e";
ctx.beginPath();
if (dir === "r") {
ctx.moveTo(x, y);
ctx.lineTo(x - 8, y - 4);
ctx.lineTo(x - 8, y + 4);
} else {
ctx.moveTo(x, y);
ctx.lineTo(x - 4, y + 8);
ctx.lineTo(x + 4, y + 8);
}
ctx.closePath();
ctx.fill();
};
arrow(w, oy, "r");
arrow(ox, 0, "u");
// Origin label
ctx.fillStyle = "#a8a29e";
ctx.font = "10px ui-monospace, monospace";
ctx.textAlign = "right";
ctx.textBaseline = "top";
ctx.fillText("0", ox - 5, oy + 4);
// ── Plot each equation ────────────────────────────────────────────────────
const xMin = vp.cx - w / (2 * vp.scale);
const xMax = vp.cx + w / (2 * vp.scale);
const steps = w * 2;
const dx = (xMax - xMin) / steps;
equations.forEach((eq, idx) => {
const fn = compiledFns[idx];
const color = eq.color ?? DEFAULT_COLORS[idx % DEFAULT_COLORS.length];
ctx.strokeStyle = color;
ctx.lineWidth = 2.5;
ctx.lineJoin = "round";
ctx.lineCap = "round";
ctx.setLineDash([]);
ctx.beginPath();
let penDown = false;
let prevY = NaN;
for (let i = 0; i <= steps; i++) {
const mx = xMin + i * dx;
const my = fn(mx);
if (!isFinite(my)) {
penDown = false;
prevY = NaN;
continue;
}
// Break line on discontinuities (asymptotes)
if (Math.abs(my - prevY) > (h / vp.scale) * 2) {
penDown = false;
}
const { sx, sy } = toScreen(mx, my, vp, canvasSize);
if (!penDown) {
ctx.moveTo(sx, sy);
penDown = true;
} else {
ctx.lineTo(sx, sy);
}
prevY = my;
}
ctx.stroke();
});
// ── Intersection dots ─────────────────────────────────────────────────────
activeIntersections.forEach((pt) => {
const { sx, sy } = toScreen(pt.x, pt.y, vp, canvasSize);
if (sx < 0 || sx > w || sy < 0 || sy > h) return;
// Outer glow ring
ctx.beginPath();
ctx.arc(sx, sy, 9, 0, Math.PI * 2);
ctx.fillStyle = "rgba(255,255,255,0.8)";
ctx.fill();
// Dot
ctx.beginPath();
ctx.arc(sx, sy, 5, 0, Math.PI * 2);
ctx.fillStyle = "#1c1917";
ctx.fill();
ctx.beginPath();
ctx.arc(sx, sy, 3, 0, Math.PI * 2);
ctx.fillStyle = "#fafaf9";
ctx.fill();
});
}, [
viewport,
canvasSize,
equations,
compiledFns,
activeIntersections,
toScreen,
]);
// ── Event handlers ────────────────────────────────────────────────────────
const zoom = useCallback(
(factor: number, pivotSx: number, pivotSy: number) => {
setViewport((vp) => {
const { mx, my } = toMath(pivotSx, pivotSy, vp, canvasSize);
const newScale = Math.max(5, Math.min(2000, vp.scale * factor));
return {
scale: newScale,
cx: mx - (pivotSx - canvasSize.w / 2) / newScale,
cy: my + (pivotSy - canvasSize.h / 2) / newScale,
};
});
},
[toMath, canvasSize],
);
const onWheel = useCallback(
(e: React.WheelEvent) => {
e.preventDefault();
const rect = canvasRef.current!.getBoundingClientRect();
const sx = e.clientX - rect.left;
const sy = e.clientY - rect.top;
const factor = e.deltaY < 0 ? 1.12 : 1 / 1.12;
zoom(factor, sx, sy);
},
[zoom],
);
const onPointerDown = useCallback((e: React.PointerEvent) => {
isPanning.current = true;
lastPointer.current = { x: e.clientX, y: e.clientY };
(e.target as HTMLElement).setPointerCapture(e.pointerId);
}, []);
const onPointerMove = useCallback((e: React.PointerEvent) => {
if (!isPanning.current) return;
const dx = e.clientX - lastPointer.current.x;
const dy = e.clientY - lastPointer.current.y;
lastPointer.current = { x: e.clientX, y: e.clientY };
setViewport((vp) => ({
...vp,
cx: vp.cx - dx / vp.scale,
cy: vp.cy + dy / vp.scale,
}));
}, []);
const onPointerUp = useCallback((e: React.PointerEvent) => {
isPanning.current = false;
}, []);
// Touch pinch-to-zoom
const onTouchStart = useCallback((e: React.TouchEvent) => {
if (e.touches.length === 2) {
const dx = e.touches[0].clientX - e.touches[1].clientX;
const dy = e.touches[0].clientY - e.touches[1].clientY;
lastPinchDist.current = Math.hypot(dx, dy);
}
}, []);
const onTouchMove = useCallback(
(e: React.TouchEvent) => {
if (e.touches.length === 2 && lastPinchDist.current !== null) {
e.preventDefault();
const dx = e.touches[0].clientX - e.touches[1].clientX;
const dy = e.touches[0].clientY - e.touches[1].clientY;
const dist = Math.hypot(dx, dy);
const factor = dist / lastPinchDist.current;
lastPinchDist.current = dist;
const rect = canvasRef.current!.getBoundingClientRect();
const pivotX =
(e.touches[0].clientX + e.touches[1].clientX) / 2 - rect.left;
const pivotY =
(e.touches[0].clientY + e.touches[1].clientY) / 2 - rect.top;
zoom(factor, pivotX, pivotY);
}
},
[zoom],
);
// Tap to find nearest intersection
const onCanvasClick = useCallback(
(e: React.MouseEvent) => {
const rect = canvasRef.current!.getBoundingClientRect();
const sx = e.clientX - rect.left;
const sy = e.clientY - rect.top;
const { mx, my } = toMath(sx, sy, viewport, canvasSize);
// Find closest intersection within 20px
let best: Intersection | null = null;
let bestDist = Infinity;
for (const pt of activeIntersections) {
const { sx: px, sy: py } = toScreen(pt.x, pt.y, viewport, canvasSize);
const d = Math.hypot(px - sx, py - sy);
if (d < 24 && d < bestDist) {
best = pt;
bestDist = d;
}
}
if (best) {
const { sx: px, sy: py } = toScreen(
best.x,
best.y,
viewport,
canvasSize,
);
setTooltip({
screenX: px,
screenY: py,
mathX: best.x,
mathY: best.y,
eqA: best.eqA,
eqB: best.eqB,
});
} else {
setTooltip(null);
}
},
[activeIntersections, toMath, toScreen, viewport, canvasSize],
);
const fmt = (n: number) => {
if (Math.abs(n) < 1e-9) return "0";
if (Math.abs(n) >= 1e4 || (Math.abs(n) < 1e-3 && n !== 0))
return n.toExponential(3);
return parseFloat(n.toFixed(4)).toString();
};
const resetView = () => setViewport({ cx: 0, cy: 0, scale: 60 });
// ── Render ─────────────────────────────────────────────────────────────────
return (
<div
ref={containerRef}
style={{ width, height, position: "relative", userSelect: "none" }}
className="rounded-2xl overflow-hidden border border-stone-200 shadow-md bg-stone-50 font-mono pt-32"
>
<canvas
ref={canvasRef}
style={{ display: "block", cursor: "crosshair", touchAction: "none" }}
onWheel={onWheel}
onPointerDown={onPointerDown}
onPointerMove={onPointerMove}
onPointerUp={onPointerUp}
onPointerCancel={onPointerUp}
onTouchStart={onTouchStart}
onTouchMove={onTouchMove}
onClick={onCanvasClick}
/>
{/* Equation legend */}
<div className="absolute top-3 left-3 flex flex-col gap-1.5">
{equations.map((eq, idx) => (
<div
key={idx}
className="flex items-center gap-2 px-2.5 py-1 rounded-lg bg-white/80 backdrop-blur-sm border border-stone-200 shadow-sm"
>
<span
className="block w-3 h-3 rounded-full shrink-0"
style={{
backgroundColor:
eq.color ?? DEFAULT_COLORS[idx % DEFAULT_COLORS.length],
}}
/>
<span className="text-[11px] text-stone-600 leading-none">
{eq.label ?? `y = ${eq.fn}`}
</span>
</div>
))}
</div>
{/* Controls */}
<div className="absolute top-3 right-3 flex flex-col gap-1.5">
<button
onClick={() => zoom(1.25, canvasSize.w / 2, canvasSize.h / 2)}
className="w-8 h-8 rounded-lg bg-white/90 border border-stone-200 shadow-sm text-stone-600 hover:bg-stone-100 transition text-lg flex items-center justify-center"
title="Zoom in"
>
+
</button>
<button
onClick={() => zoom(1 / 1.25, canvasSize.w / 2, canvasSize.h / 2)}
className="w-8 h-8 rounded-lg bg-white/90 border border-stone-200 shadow-sm text-stone-600 hover:bg-stone-100 transition text-lg flex items-center justify-center"
title="Zoom out"
>
</button>
<button
onClick={resetView}
className="w-8 h-8 rounded-lg bg-white/90 border border-stone-200 shadow-sm text-stone-500 hover:bg-stone-100 transition text-[10px] flex items-center justify-center font-sans"
title="Reset view"
>
</button>
</div>
{/* Intersection tooltip */}
{tooltip && (
<div
className="absolute z-10 pointer-events-none"
style={{
left: tooltip.screenX,
top: tooltip.screenY,
transform: "translate(-50%, -130%)",
}}
>
<div className="bg-stone-900 text-stone-100 text-[11px] px-3 py-2 rounded-xl shadow-xl border border-stone-700 whitespace-nowrap">
<div className="font-semibold mb-0.5 text-stone-300 text-[10px] tracking-wide uppercase">
Intersection
</div>
<div>
x ={" "}
<span className="text-amber-300 font-bold">
{fmt(tooltip.mathX)}
</span>
</div>
<div>
y ={" "}
<span className="text-amber-300 font-bold">
{fmt(tooltip.mathY)}
</span>
</div>
<div className="text-stone-500 text-[9px] mt-1">
eq {tooltip.eqA + 1} eq {tooltip.eqB + 1}
</div>
</div>
{/* Arrow */}
<div className="flex justify-center">
<div className="w-2 h-2 bg-stone-900 rotate-45 -mt-1 border-r border-b border-stone-700" />
</div>
</div>
)}
{/* Dismiss tooltip on background click hint */}
{tooltip && (
<button
className="absolute inset-0 w-full h-full bg-transparent"
onClick={() => setTooltip(null)}
style={{ zIndex: 5 }}
/>
)}
</div>
);
};

View File

@ -0,0 +1,825 @@
import { useEffect, useRef, useState } from "react";
import { ChevronDown, ChevronRight, Gauge, Map } from "lucide-react";
import { useNavigate } from "react-router-dom";
import { useAuthStore } from "../stores/authStore";
import {
useQuestStore,
getQuestSummary,
getCrewRank,
} from "../stores/useQuestStore";
import type {
QuestNode,
QuestArc,
ClaimedRewardResponse,
} from "../types/quest";
import { CREW_RANKS } from "../types/quest";
import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar";
import { Drawer, DrawerContent, DrawerTrigger } from "./ui/drawer";
import { PredictedScoreCard } from "./PredictedScoreCard";
import { ChestOpenModal } from "./ChestOpenModal";
// Re-use the same theme generator that QuestMap uses so arc colours are consistent
import { generateArcTheme } from "../pages/student/QuestMap";
import { InventoryButton } from "./InventoryButton";
// ─── Requirement helpers (mirrors QuestMap) ───────────────────────────────────
const REQ_EMOJI: Record<string, string> = {
questions: "❓",
accuracy: "🎯",
streak: "🔥",
sessions: "📚",
topics: "🗺️",
xp: "⚡",
leaderboard: "🏆",
};
const REQ_LABEL: Record<string, string> = {
questions: "questions answered",
accuracy: "% accuracy",
streak: "day streak",
sessions: "sessions",
topics: "topics covered",
xp: "XP earned",
leaderboard: "leaderboard rank",
};
// ─── Styles ───────────────────────────────────────────────────────────────────
const STYLES = `
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@700;800;900&family=Nunito+Sans:wght@400;600;700&family=Cinzel:wght@700;900&display=swap');
/* ════ SHARED ANIMATION ════ */
@keyframes hcIn {
from { opacity:0; transform:translateY(10px) scale(0.97); }
to { opacity:1; transform:translateY(0) scale(1); }
}
/* ════ WHITE CARD (DEFAULT / LEVEL / QUEST_COMPACT) ════ */
.hc-card {
background: white;
border: 2.5px solid #f3f4f6;
border-radius: 26px;
box-shadow: 0 4px 20px rgba(0,0,0,0.06);
overflow: hidden;
animation: hcIn 0.4s cubic-bezier(0.34,1.56,0.64,1) both;
}
/* Identity */
.hc-top {
display: flex; align-items: center;
justify-content: space-between; gap: 0.75rem;
padding: 1.1rem 1.2rem 0.9rem;
}
.hc-identity { display: flex; align-items: center; gap: 0.7rem; flex: 1; min-width: 0; }
.hc-av-wrap { position: relative; flex-shrink: 0; }
.hc-av-pip {
position: absolute; bottom: -3px; right: -3px;
min-width: 18px; height: 18px; border-radius: 9px; padding: 0 4px;
background: linear-gradient(135deg, #a855f7, #7c3aed);
border: 2px solid white;
display: flex; align-items: center; justify-content: center;
font-family: 'Nunito', sans-serif;
font-size: 0.55rem; font-weight: 900; color: white;
}
.hc-nameblock { flex: 1; min-width: 0; }
.hc-greeting {
font-family: 'Nunito', sans-serif;
font-size: 0.98rem; font-weight: 900; color: #1e1b4b;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.2;
}
.hc-greeting em { font-style: normal; color: #a855f7; }
.hc-role {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.63rem; font-weight: 700; letter-spacing: 0.09em;
text-transform: uppercase; color: #9ca3af; margin-top: 0.05rem;
}
.hc-score-btn {
display: flex; align-items: center; gap: 0.3rem;
background: #f7ffe4; border: 2px solid #d9f99d; border-radius: 100px;
padding: 0.42rem 0.72rem; font-family: 'Nunito', sans-serif;
font-size: 0.76rem; font-weight: 800; color: #65a30d;
cursor: pointer; flex-shrink: 0;
transition: transform 0.15s, box-shadow 0.15s;
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
}
.hc-score-btn:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,0.07); }
.hc-sep { height: 1px; margin: 0 1.2rem; background: #f3f4f6; }
/* XP bar */
.hc-xp-row { display: flex; align-items: center; gap: 0.75rem; padding: 0.85rem 1.2rem; }
.hc-lvl-tag {
font-family: 'Nunito', sans-serif; font-size: 0.7rem; font-weight: 900;
color: #a855f7; flex-shrink: 0; background: #f3e8ff;
border-radius: 8px; padding: 0.22rem 0.5rem; white-space: nowrap;
}
.hc-bar-wrap { flex: 1; display: flex; flex-direction: column; gap: 0.22rem; }
.hc-track { height: 8px; background: #f3f4f6; border-radius: 100px; overflow: hidden; }
.hc-fill {
height: 100%; border-radius: 100px;
background: linear-gradient(90deg, #a855f7, #f97316);
transition: width 1.1s cubic-bezier(0.34,1.56,0.64,1);
position: relative; overflow: hidden;
}
.hc-fill::after {
content: ''; position: absolute; inset: 0;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
transform: translateX(-100%);
animation: hcShimmer 2.6s ease-in-out 1s infinite;
}
@keyframes hcShimmer { to { transform: translateX(200%); } }
.hc-xp-label {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.6rem; font-weight: 700; color: #9ca3af;
display: flex; justify-content: space-between;
}
.hc-xp-label span:first-child { color: #a855f7; font-weight: 900; }
/* Rank row (compact) */
.hc-rank-row {
display: flex; align-items: center; gap: 0.6rem;
padding: 0.75rem 1.2rem; cursor: pointer;
transition: background 0.15s; border-top: 1px solid #f3f4f6;
}
.hc-rank-row:first-child { border-top: none; }
.hc-rank-row:hover { background: #fafafa; }
.hc-rank-emoji { font-size: 1.15rem; flex-shrink: 0; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1)); }
.hc-rank-text { flex: 1; min-width: 0; }
.hc-rank-name {
font-family: 'Cinzel', serif; font-size: 0.8rem; font-weight: 700; color: #1e1b4b;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hc-rank-progress-label {
font-family: 'Nunito Sans', sans-serif; font-size: 0.58rem; font-weight: 700;
color: #9ca3af; margin-top: 0.08rem;
}
.hc-rank-right { display: flex; align-items: center; gap: 0.4rem; flex-shrink: 0; }
.hc-streak-pill {
display: flex; align-items: center; gap: 0.22rem;
background: #fff5f5; border: 1.5px solid #fecaca; border-radius: 100px;
padding: 0.2rem 0.5rem; font-family: 'Nunito', sans-serif;
font-size: 0.7rem; font-weight: 900; color: #ef4444;
}
.hc-chest-badge {
display: flex; align-items: center; gap: 0.18rem;
background: #fef3c7; border: 1.5px solid #fde68a; border-radius: 100px;
padding: 0.2rem 0.5rem; font-family: 'Nunito', sans-serif;
font-size: 0.7rem; font-weight: 900; color: #b45309;
animation: hcPop 1.8s ease-in-out infinite;
}
@keyframes hcPop { 0%,100%{transform:scale(1);} 50%{transform:scale(1.07);} }
.hc-chevron { color: #d1d5db; transition: transform 0.3s cubic-bezier(0.34,1.56,0.64,1), color 0.2s; }
.hc-chevron.open { transform: rotate(180deg); color: #a855f7; }
/* Collapsible quest panel */
.hc-quests-wrap {
overflow: hidden; max-height: 0;
transition: max-height 0.38s cubic-bezier(0.4,0,0.2,1);
background: #fafafa; border-top: 1px solid #f3f4f6;
}
.hc-quests-wrap.open { max-height: 480px; }
.hc-quest-list { display: flex; flex-direction: column; padding: 0.35rem 0; }
.hc-quest-row {
display: flex; align-items: center; gap: 0.6rem;
padding: 0.65rem 1.2rem; cursor: pointer; transition: background 0.13s; position: relative;
}
.hc-quest-row:hover { background: #f3f4f6; }
.hc-quest-row::before {
content: ''; position: absolute; left: 0; top: 20%; bottom: 20%;
width: 3px; border-radius: 0 3px 3px 0; background: var(--ac);
}
.hc-q-icon {
width: 34px; height: 34px; border-radius: 10px; flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
font-size: 1rem; background: white; border: 1.5px solid #f3f4f6;
transition: transform 0.15s;
}
.hc-quest-row:hover .hc-q-icon { transform: scale(1.08) rotate(-4deg); }
.hc-q-icon.claimable { background: #fef3c7; border-color: #fde68a; animation: hcWiggle 2s ease-in-out infinite; }
@keyframes hcWiggle { 0%,100%{transform:rotate(0);} 30%{transform:rotate(-7deg) scale(1.05);} 70%{transform:rotate(7deg) scale(1.05);} }
.hc-q-body { flex: 1; min-width: 0; }
.hc-q-name { font-family: 'Nunito', sans-serif; font-size: 0.8rem; font-weight: 800; color: #1e1b4b; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hc-q-sub { font-family: 'Nunito Sans', sans-serif; font-size: 0.62rem; font-weight: 600; color: #9ca3af; margin-top: 0.1rem; }
.hc-q-claimable { font-family: 'Nunito Sans', sans-serif; font-size: 0.62rem; font-weight: 700; color: #d97706; margin-top: 0.1rem; }
.hc-claim-btn {
padding: 0.28rem 0.62rem; border: none; border-radius: 100px; cursor: pointer;
background: linear-gradient(135deg, #fbbf24, #f59e0b);
font-family: 'Nunito', sans-serif; font-size: 0.65rem; font-weight: 900; color: #1a0800;
box-shadow: 0 2px 0 #d97706; flex-shrink: 0; transition: all 0.12s;
}
.hc-claim-btn:hover { transform: translateY(-1px); }
.hc-claim-btn:active { transform: translateY(1px); }
.hc-empty { padding: 1rem 1.2rem; text-align: center; font-family: 'Nunito', sans-serif; font-size: 0.82rem; font-weight: 700; color: #9ca3af; }
.hc-map-link {
display: flex; align-items: center; justify-content: center; gap: 0.3rem;
padding: 0.6rem 1.2rem; border-top: 1px solid #f3f4f6;
cursor: pointer; transition: background 0.13s;
font-family: 'Nunito', sans-serif; font-size: 0.7rem; font-weight: 800; color: #a855f7;
}
.hc-map-link:hover { background: #fdf4ff; }
/* ════ DARK OCEAN CARD (QUEST_EXTENDED) ════ */
.hc-ext {
background: linear-gradient(160deg, #0b1a35 0%, #060e1f 55%, #0d1530 100%);
border-radius: 26px; overflow: hidden; position: relative;
box-shadow: 0 8px 32px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.06);
animation: hcIn 0.4s cubic-bezier(0.34,1.56,0.64,1) both;
margin-bottom: 12px;
}
.hc-ext::before {
content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 0;
background:
repeating-linear-gradient(105deg, transparent 55%, rgba(56,189,248,0.018) 56%, transparent 57%),
repeating-linear-gradient(75deg, transparent 70%, rgba(56,189,248,0.012) 71%, transparent 72%);
background-size: 320% 320%, 260% 260%;
animation: hcExtSea 14s ease-in-out infinite alternate;
}
@keyframes hcExtSea {
0% { background-position: 0% 0%, 100% 0%; }
100% { background-position: 100% 100%, 0% 100%; }
}
.hc-ext::after {
content: ''; position: absolute; top: -40px; right: -30px; z-index: 0;
width: 180px; height: 180px; border-radius: 50%;
background: radial-gradient(circle, rgba(251,191,36,0.1), transparent 70%);
pointer-events: none;
}
.hc-ext-header {
position: relative; z-index: 2;
display: flex; align-items: center; justify-content: space-between;
padding: 1rem 1.2rem 0.3rem;
}
.hc-ext-title {
font-family: 'Cinzel', serif; font-size: 0.6rem; font-weight: 700;
letter-spacing: 0.2em; text-transform: uppercase; color: rgba(251,191,36,0.65);
}
.hc-ext-earned {
font-family: 'Nunito', sans-serif; font-size: 0.7rem; font-weight: 900;
color: #fbbf24; background: rgba(251,191,36,0.1);
border: 1px solid rgba(251,191,36,0.18); border-radius: 100px;
padding: 0.2rem 0.6rem;
}
.hc-ext-scroll {
position: relative; z-index: 2;
overflow-x: auto; overflow-y: hidden;
-webkit-overflow-scrolling: touch; scrollbar-width: none;
cursor: grab; padding: 1.0rem 1.0rem 0.8rem;
}
.hc-ext-scroll::-webkit-scrollbar { display: none; }
.hc-ext-scroll:active { cursor: grabbing; }
.hc-ext-inner {
display: flex; align-items: flex-end;
position: relative;
height: 110px;
}
.hc-ext-baseline {
position: absolute;
top: 56px; left: 26px; right: 26px; height: 2px;
background: rgba(255,255,255,0.07);
border-radius: 2px; z-index: 0;
}
.hc-ext-progress-line {
position: absolute;
top: 56px; left: 26px; height: 2px;
background: linear-gradient(90deg, #fbbf24, #f59e0b);
box-shadow: 0 0 10px rgba(251,191,36,0.5);
border-radius: 2px; z-index: 1;
transition: width 1.2s cubic-bezier(0.34,1.56,0.64,1);
}
.hc-ext-ship-wrap {
position: absolute;
top: 25px; z-index: 10; pointer-events: none;
display: flex; flex-direction: column; align-items: center; gap: 0px;
transition: left 1.2s cubic-bezier(0.34,1.56,0.64,1);
transform: translateX(-50%);
}
.hc-ext-ship {
font-size: 1.5rem;
filter: drop-shadow(0 2px 12px rgba(251,191,36,0.6));
animation: hcShipBob 2.8s ease-in-out infinite;
display: block;
}
@keyframes hcShipBob {
0%,100% { transform: translateY(0) rotate(-3deg); }
50% { transform: translateY(-6px) rotate(3deg); }
}
.hc-ext-ship-tether {
width: 1px; height: 14px;
background: linear-gradient(to bottom, rgba(251,191,36,0.5), transparent);
}
.hc-ext-col {
display: flex; flex-direction: column; align-items: center;
position: relative; z-index: 2;
width: 88px; flex-shrink: 0;
}
.hc-ext-col:first-child,
.hc-ext-col:last-child { width: 52px; }
.hc-ext-node {
width: 52px; height: 52px; border-radius: 50%; flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
font-size: 1.4rem; position: relative; z-index: 2;
margin-top: 42px;
}
.hc-ext-node.reached {
background: linear-gradient(145deg, #1e0e4a, #3730a3);
border: 2px solid rgba(251,191,36,0.45);
box-shadow: 0 0 18px rgba(251,191,36,0.2), 0 4px 0 rgba(20,10,50,0.7);
}
.hc-ext-node.current {
background: linear-gradient(145deg, #6d28d9, #a855f7);
border: 2.5px solid #fbbf24;
box-shadow:
0 0 0 4px rgba(251,191,36,0.12),
0 0 22px rgba(168,85,247,0.45),
0 4px 0 rgba(80,30,150,0.5);
animation: hcExtNodePulse 2.2s ease-in-out infinite;
}
@keyframes hcExtNodePulse {
0%,100% { box-shadow: 0 0 0 4px rgba(251,191,36,0.12), 0 0 22px rgba(168,85,247,0.45), 0 4px 0 rgba(80,30,150,0.5); }
50% { box-shadow: 0 0 0 7px rgba(251,191,36,0.06), 0 0 30px rgba(168,85,247,0.6), 0 4px 0 rgba(80,30,150,0.5); }
}
.hc-ext-node.locked {
background: rgba(0,0,0,0.4);
border: 2px solid rgba(255,255,255,0.09);
filter: grayscale(0.7) opacity(0.45);
}
.hc-ext-label {
margin-top: 7px;
display: flex; flex-direction: column; align-items: center; gap: 2px;
}
.hc-ext-label-name {
font-family: 'Cinzel', serif; font-size: 0.48rem; font-weight: 700;
text-align: center; line-height: 1.3; letter-spacing: 0.03em; max-width: 70px;
}
.hc-ext-label-name.reached { color: #fbbf24; }
.hc-ext-label-name.current { color: #c084fc; }
.hc-ext-label-name.locked { color: rgba(255,255,255,0.2); }
.hc-ext-label-xp {
font-family: 'Nunito Sans', sans-serif; font-size: 0.42rem; font-weight: 700;
text-align: center;
}
.hc-ext-label-xp.reached { color: rgba(251,191,36,0.4); }
.hc-ext-label-xp.current { color: rgba(192,132,252,0.6); }
.hc-ext-label-xp.locked { color: rgba(255,255,255,0.15); }
.hc-ext-footer {
position: relative; z-index: 2;
display: flex; align-items: center; justify-content: center; gap: 0.3rem;
padding: 0.5rem 1.2rem 0.85rem; margin-top: 0.2rem;
border-top: 1px solid rgba(255,255,255,0.06);
cursor: pointer; transition: opacity 0.15s;
font-family: 'Nunito', sans-serif; font-size: 0.68rem; font-weight: 800;
color: rgba(251,191,36,0.55); letter-spacing: 0.04em;
}
.hc-ext-footer:hover { opacity: 0.75; }
`;
// ─── Helpers ──────────────────────────────────────────────────────────────────
function getActiveQuests(arcs: QuestArc[]) {
const out: { node: QuestNode; arc: QuestArc }[] = [];
for (const arc of arcs)
for (const node of arc.nodes)
if (node.status === "claimable" || node.status === "active")
out.push({ node, arc });
// Claimable nodes bubble to the top
out.sort((a, b) =>
a.node.status === "claimable" && b.node.status !== "claimable"
? -1
: b.node.status === "claimable" && a.node.status !== "claimable"
? 1
: 0,
);
return out.slice(0, 2);
}
const SEG_W = 88;
const EDGE_W = 52;
function nodeX(i: number, total: number): number {
if (i === 0) return EDGE_W / 2;
if (i === total - 1) return EDGE_W / 2 + SEG_W * (total - 2) + EDGE_W / 2;
return EDGE_W + SEG_W * (i - 1) + SEG_W / 2;
}
// ─── QUEST_EXTENDED sub-component ────────────────────────────────────────────
const RankLadder = ({
earnedXP,
}: {
earnedXP: number;
onViewAll: () => void;
}) => {
const scrollRef = useRef<HTMLDivElement>(null);
const ladder = [...CREW_RANKS] as typeof CREW_RANKS;
const N = ladder.length;
let currentIdx = 0;
for (let i = N - 1; i >= 0; i--) {
if (earnedXP >= ladder[i].xpRequired) {
currentIdx = i;
break;
}
}
const current = ladder[currentIdx];
const nextRank = ladder[currentIdx + 1] ?? null;
const progressToNext = nextRank
? Math.min(
1,
(earnedXP - current.xpRequired) /
(nextRank.xpRequired - current.xpRequired),
)
: 1;
const shipX = nextRank
? nodeX(currentIdx, N) +
(nodeX(currentIdx + 1, N) - nodeX(currentIdx, N)) * progressToNext
: nodeX(currentIdx, N);
const progressLineW = shipX;
const totalW = EDGE_W + SEG_W * (N - 2) + EDGE_W;
const [animated, setAnimated] = useState(false);
useEffect(() => {
const id = requestAnimationFrame(() =>
requestAnimationFrame(() => setAnimated(true)),
);
return () => cancelAnimationFrame(id);
}, []);
useEffect(() => {
if (!scrollRef.current) return;
const el = scrollRef.current;
el.scrollTo({
left: Math.max(0, shipX - el.offsetWidth / 2),
behavior: "smooth",
});
}, [shipX]);
const rankPct = nextRank ? Math.round(progressToNext * 100) : 100;
const nextLabel = nextRank
? `${rankPct}% · ${nextRank.xpRequired - earnedXP} XP to ${nextRank.label}`
: "Maximum rank achieved";
return (
<div className="hc-ext">
<div className="hc-ext-header">
<span className="hc-ext-title"> Crew Rank</span>
<span className="hc-ext-earned">{earnedXP.toLocaleString()} XP</span>
</div>
<div
style={{
position: "relative",
zIndex: 2,
padding: "0 1.2rem 0.1rem",
display: "flex",
alignItems: "baseline",
gap: "0.4rem",
}}
>
<span
style={{
fontFamily: "'Cinzel', serif",
fontSize: "1.05rem",
fontWeight: 900,
color: "#fbbf24",
textShadow: "0 0 18px rgba(251,191,36,0.4)",
}}
>
{current.emoji} {current.label}
</span>
<span
style={{
fontFamily: "'Nunito Sans', sans-serif",
fontSize: "0.6rem",
fontWeight: 700,
color: "rgba(255,255,255,0.3)",
}}
>
{nextLabel}
</span>
</div>
<div className="hc-ext-scroll" ref={scrollRef}>
<div className="hc-ext-inner" style={{ width: totalW }}>
<div className="hc-ext-baseline" />
<div
className="hc-ext-progress-line"
style={{ width: animated ? progressLineW : 26 }}
/>
<div
className="hc-ext-ship-wrap"
style={{ left: animated ? shipX : nodeX(0, N) }}
>
<span className="hc-ext-ship" role="img" aria-label="ship">
</span>
<div className="hc-ext-ship-tether" />
</div>
{ladder.map((r, i) => {
const state =
i < currentIdx
? "reached"
: i === currentIdx
? "current"
: "locked";
return (
<div key={r.id} className="hc-ext-col">
<div className={`hc-ext-node ${state}`}>{r.emoji}</div>
<div className="hc-ext-label">
<span className={`hc-ext-label-name ${state}`}>
{r.label}
</span>
<span className={`hc-ext-label-xp ${state}`}>
{r.xpRequired === 0
? "Start"
: `${r.xpRequired.toLocaleString()} XP`}
</span>
</div>
</div>
);
})}
</div>
</div>
</div>
);
};
// ─── Props ────────────────────────────────────────────────────────────────────
type Mode = "DEFAULT" | "LEVEL" | "QUEST_COMPACT" | "QUEST_EXTENDED";
interface Props {
onViewAll?: () => void;
mode?: Mode;
}
// ─── Main component ───────────────────────────────────────────────────────────
export const InfoHeader = ({ onViewAll, mode = "DEFAULT" }: Props) => {
const navigate = useNavigate();
const user = useAuthStore((s) => s.user);
// Select all needed store slices — earnedXP and earnedTitles are now first-class state
const arcs = useQuestStore((s) => s.arcs);
const earnedXP = user?.total_xp ?? 0;
const earnedTitles = useQuestStore((s) => s.earnedTitles);
const claimNode = useQuestStore((s) => s.claimNode);
// Updated signatures: getQuestSummary needs earnedXP + earnedTitles,
// getCrewRank takes earnedXP directly (no longer iterates nodes)
const summary = getQuestSummary(arcs, earnedXP, earnedTitles);
const rank = getCrewRank(earnedXP);
const activeQuests = getActiveQuests(arcs);
const u = user as any;
const level = u?.current_level ?? 1;
const totalXP = u?.total_xp ?? 5;
const levelStart = u?.current_level_start ?? u?.level_min_xp ?? 0;
const levelEnd =
u?.next_level_threshold ?? u?.level_max_xp ?? levelStart + 1000;
const streak = u?.streak ?? u?.current_streak ?? 0;
const firstName = user?.name?.split(" ")[0] || "there";
const roleLabel =
u?.role === "ADMIN"
? "Admin"
: u?.role === "TEACHER"
? "Teacher"
: "Student";
const hour = new Date().getHours();
const timeLabel = hour < 12 ? "morning" : hour < 17 ? "afternoon" : "evening";
const levelRange = Math.max(levelEnd - levelStart, 1);
const xpIntoLevel = Math.max(totalXP - levelStart, 0);
const rawPct = Math.min(Math.round((xpIntoLevel / levelRange) * 100), 100);
const xpToGo = Math.max(levelEnd - totalXP, 0);
const [barPct, setBarPct] = useState(0);
useEffect(() => {
const id = requestAnimationFrame(() =>
requestAnimationFrame(() => setBarPct(rawPct)),
);
return () => cancelAnimationFrame(id);
}, [rawPct]);
const [open, setOpen] = useState(false);
const [claimingNode, setClaimingNode] = useState<{
node: QuestNode;
arcId: string;
} | null>(null);
// Holds the API response from the claim call so ChestOpenModal can display real rewards
const [claimResult, setClaimResult] = useState<ClaimedRewardResponse | null>(
null,
);
const handleViewAll = () => {
if (onViewAll) onViewAll();
else navigate("/student/quests");
};
const handleClaim = (node: QuestNode, arcId: string) => {
setClaimResult(null); // clear any previous result before opening
setClaimingNode({ node, arcId });
};
const handleChestClose = () => {
if (!claimingNode) return;
claimNode(
claimingNode.arcId,
claimingNode.node.node_id, // node_id replaces old id
claimResult?.xp_awarded ?? 0,
claimResult?.title_unlocked.map((t) => t.name) ?? [],
);
setClaimingNode(null);
setClaimResult(null);
};
const rankProgress = Math.round(rank.progressToNext * 100);
const nextLabel = rank.next
? `${rankProgress}% to ${rank.next.label}`
: "Max rank";
const showIdentity = mode === "DEFAULT";
const showLevel = mode === "DEFAULT" || mode === "LEVEL";
const showQuestCompact = mode === "DEFAULT" || mode === "QUEST_COMPACT";
const showQuestExtended = mode === "QUEST_EXTENDED";
if (showQuestExtended) {
return (
<>
<style>{STYLES}</style>
<RankLadder earnedXP={earnedXP} onViewAll={handleViewAll} />
{claimingNode && (
<ChestOpenModal
node={claimingNode.node}
claimResult={claimResult}
onClose={handleChestClose}
/>
)}
</>
);
}
return (
<>
<style>{STYLES}</style>
<div className="hc-card">
{/* Identity — DEFAULT only */}
{showIdentity && (
<>
<div className="hc-top">
<div className="hc-identity">
<div className="hc-av-wrap">
<Avatar style={{ width: 46, height: 46, display: "block" }}>
<AvatarImage src={u?.avatar_url} />
<AvatarFallback
style={{
fontWeight: 900,
fontSize: "1rem",
color: "white",
textTransform: "uppercase",
background: "linear-gradient(135deg,#a855f7,#7c3aed)",
}}
>
{user?.name?.slice(0, 1)}
</AvatarFallback>
</Avatar>
<div className="hc-av-pip">{level}</div>
</div>
<div className="hc-nameblock">
<p className="hc-greeting">
Good {timeLabel}, <em>{firstName}</em> 👋
</p>
<p className="hc-role">{roleLabel}</p>
</div>
</div>
<InventoryButton label="Inventory" />
<Drawer direction="top">
<DrawerTrigger asChild>
<button className="hc-score-btn">
<Gauge size={14} />
</button>
</DrawerTrigger>
<DrawerContent>
<PredictedScoreCard />
</DrawerContent>
</Drawer>
</div>
<div className="hc-sep" />
</>
)}
{/* XP bar — DEFAULT + LEVEL */}
{showLevel && (
<div className="hc-xp-row">
<span className="hc-lvl-tag">Lv {level}</span>
<div className="hc-bar-wrap">
<div className="hc-track">
<div className="hc-fill" style={{ width: `${barPct}%` }} />
</div>
<div className="hc-xp-label">
<span>{totalXP.toLocaleString()} XP</span>
<span>{xpToGo.toLocaleString()} to go</span>
</div>
</div>
</div>
)}
{/* Rank + collapsible quests — DEFAULT + QUEST_COMPACT */}
{showQuestCompact && (
<>
<div className="hc-rank-row" onClick={() => setOpen((o) => !o)}>
<span className="hc-rank-emoji">{rank.emoji}</span>
<div className="hc-rank-text">
<p className="hc-rank-name">{rank.label}</p>
<p className="hc-rank-progress-label">{nextLabel}</p>
</div>
<div className="hc-rank-right">
{streak > 0 && (
<span className="hc-streak-pill">🔥 {streak}</span>
)}
{summary.claimableNodes > 0 && (
<span className="hc-chest-badge">
📦 {summary.claimableNodes}
</span>
)}
<ChevronDown
size={16}
className={`hc-chevron${open ? " open" : ""}`}
/>
</div>
</div>
<div className={`hc-quests-wrap${open ? " open" : ""}`}>
<div className="hc-quest-list">
{activeQuests.length === 0 ? (
<p className="hc-empty"> All caught up keep sailing!</p>
) : (
activeQuests.map(({ node, arc }) => {
// Progress uses new field names
const pct = Math.min(
100,
Math.round((node.current_value / node.req_target) * 100),
);
const isClaimable = node.status === "claimable";
// Arc accent colour via theme generator — arc.accentColor no longer exists
const accentColor = generateArcTheme(arc).accent;
// Node icon derived from req_type — node.emoji no longer exists
const nodeEmoji = REQ_EMOJI[node.req_type] ?? "🏝️";
// Progress label derived from req_type — node.requirement.label no longer exists
const reqLabel = REQ_LABEL[node.req_type] ?? node.req_type;
return (
<div
key={node.node_id} // node_id replaces old id
className="hc-quest-row"
style={{ "--ac": accentColor } as React.CSSProperties}
onClick={() => !isClaimable && handleViewAll()}
>
<div
className={`hc-q-icon${isClaimable ? " claimable" : ""}`}
>
{isClaimable ? "📦" : nodeEmoji}
</div>
<div className="hc-q-body">
{/* node.name replaces old node.title */}
<p className="hc-q-name">{node.name ?? "—"}</p>
{isClaimable ? (
<p className="hc-q-claimable"> Ready to claim!</p>
) : (
<p className="hc-q-sub">
{/* current_value / req_target replace old progress / requirement.target */}
{node.current_value}/{node.req_target} {reqLabel}{" "}
· {pct}%
</p>
)}
</div>
{isClaimable ? (
<button
className="hc-claim-btn"
onClick={(e) => {
e.stopPropagation();
handleClaim(node, arc.id);
}}
>
Open
</button>
) : (
<ChevronRight size={14} color="#d1d5db" />
)}
</div>
);
})
)}
</div>
<div className="hc-map-link" onClick={handleViewAll}>
<Map size={13} /> View quest map
</div>
</div>
</>
)}
</div>
{claimingNode && (
<ChestOpenModal
node={claimingNode.node}
claimResult={claimResult}
onClose={handleChestClose}
/>
)}
</>
);
};

View File

@ -0,0 +1,217 @@
import { useState } from "react";
import {
useInventoryStore,
getLiveEffects,
formatTimeLeft,
hasActiveEffect,
} from "../stores/useInventoryStore";
import { InventoryModal } from "./InventoryModal";
// ─── Styles ───────────────────────────────────────────────────────────────────
const BTN_STYLES = `
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@800;900&family=Cinzel:wght@700&display=swap');
/* ── Inventory trigger button ── */
.inv-btn {
position: relative;
display: inline-flex; align-items: center; gap: 0.38rem;
padding: 0.48rem 0.85rem;
background: rgba(255,255,255,0.05);
border: 1.5px solid rgba(255,255,255,0.1);
border-radius: 100px;
cursor: pointer;
font-family: 'Nunito', sans-serif;
font-size: 0.72rem; font-weight: 900;
color: rgba(255,255,255,0.7);
transition: all 0.18s ease;
outline: none;
white-space: nowrap;
}
.inv-btn:hover {
background: rgba(255,255,255,0.09);
border-color: rgba(255,255,255,0.2);
color: white;
transform: translateY(-1px);
box-shadow: 0 4px 16px rgba(0,0,0,0.25);
}
.inv-btn:active { transform: translateY(0) scale(0.97); }
/* When active effects are running — gold glow */
.inv-btn.has-active {
border-color: rgba(251,191,36,0.45);
color: #fbbf24;
background: rgba(251,191,36,0.08);
animation: invBtnGlow 2.6s ease-in-out infinite;
}
@keyframes invBtnGlow {
0%,100% { box-shadow: 0 0 0 0 rgba(251,191,36,0); }
50% { box-shadow: 0 0 14px 3px rgba(251,191,36,0.2); }
}
.inv-btn.has-active:hover {
border-color: rgba(251,191,36,0.7);
background: rgba(251,191,36,0.14);
}
/* Badge dot */
.inv-btn-badge {
position: absolute; top: -4px; right: -4px;
width: 14px; height: 14px; border-radius: 50%;
background: #fbbf24;
border: 2px solid transparent; /* will be set to match parent bg via CSS var */
display: flex; align-items: center; justify-content: center;
font-family: 'Nunito', sans-serif;
font-size: 0.45rem; font-weight: 900; color: #1a0800;
animation: invBadgePop 1.8s ease-in-out infinite;
}
@keyframes invBadgePop {
0%,100%{ transform: scale(1); }
50% { transform: scale(1.15); }
}
/* ── Active Effect Banner (shown on other screens, e.g. pretest) ── */
.aeb-wrap {
display: flex; gap: 0.5rem; flex-wrap: wrap;
}
.aeb-pill {
display: inline-flex; align-items: center; gap: 0.4rem;
padding: 0.38rem 0.85rem;
border-radius: 100px;
font-family: 'Nunito', sans-serif;
font-size: 0.72rem; font-weight: 900;
animation: aebPillIn 0.35s cubic-bezier(0.34,1.56,0.64,1) both;
animation-delay: var(--aeb-delay, 0s);
}
@keyframes aebPillIn {
from { opacity:0; transform: scale(0.8) translateY(6px); }
to { opacity:1; transform: scale(1) translateY(0); }
}
/* Color variants per effect type */
.aeb-pill.xp_boost {
background: rgba(251,191,36,0.12);
border: 1.5px solid rgba(251,191,36,0.4);
color: #fbbf24;
}
.aeb-pill.streak_shield {
background: rgba(96,165,250,0.1);
border: 1.5px solid rgba(96,165,250,0.35);
color: #60a5fa;
}
.aeb-pill.coin_boost {
background: rgba(167,243,208,0.08);
border: 1.5px solid rgba(52,211,153,0.35);
color: #34d399;
}
.aeb-pill.default {
background: rgba(255,255,255,0.06);
border: 1.5px solid rgba(255,255,255,0.15);
color: rgba(255,255,255,0.7);
}
.aeb-pill-icon { font-size: 0.9rem; line-height:1; }
.aeb-pill-label { line-height:1; }
.aeb-pill-time {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.58rem; font-weight: 700;
opacity: 0.55; margin-left: 0.1rem;
}
`;
const ITEM_ICON: Record<string, string> = {
xp_boost: "⚡",
streak_shield: "🛡️",
title: "🏴‍☠️",
coin_boost: "🪙",
};
function itemIcon(effectType: string): string {
return ITEM_ICON[effectType] ?? "📦";
}
// ─── InventoryButton ──────────────────────────────────────────────────────────
/**
* Drop-in trigger button. Can be placed in any nav bar, header, or screen.
* Shows a gold glow + badge count when active effects are running.
*
* Usage:
* <InventoryButton />
* <InventoryButton label="Hold" />
*/
export const InventoryButton = ({}: {}) => {
const [open, setOpen] = useState(false);
const activeEffects = useInventoryStore((s) => s.activeEffects);
const liveEffects = getLiveEffects(activeEffects);
const hasActive = liveEffects.length > 0;
return (
<>
<style>{BTN_STYLES}</style>
<button
className={`inv-btn${hasActive ? " has-active" : ""}`}
onClick={() => setOpen(true)}
aria-label="Open inventory"
>
🎒
{hasActive && (
<span className="inv-btn-badge">{liveEffects.length}</span>
)}
</button>
{open && <InventoryModal onClose={() => setOpen(false)} />}
</>
);
};
// ─── ActiveEffectBanner ───────────────────────────────────────────────────────
/**
* Shows pills for each currently-active effect.
* Place wherever you want a contextual reminder (pretest screen, dashboard, etc.)
*
* Usage:
* <ActiveEffectBanner />
* <ActiveEffectBanner filter="xp_boost" /> ← only show a specific effect
*
* Example output on Pretest screen:
* ⚡ XP Boost ×2 · 1h 42m 🛡️ Streak Shield · 23m
*/
export const ActiveEffectBanner = ({
filter,
className,
}: {
filter?: string;
className?: string;
}) => {
const activeEffects = useInventoryStore((s) => s.activeEffects);
const live = getLiveEffects(activeEffects).filter(
(e) => !filter || e.item.effect_type === filter,
);
if (live.length === 0) return null;
return (
<>
<style>{BTN_STYLES}</style>
<div className={`aeb-wrap${className ? ` ${className}` : ""}`}>
{live.map((e, i) => (
<div
key={e.id}
className={`aeb-pill ${e.item.effect_type ?? "default"}`}
style={{ "--aeb-delay": `${i * 0.07}s` } as React.CSSProperties}
>
<span className="aeb-pill-icon">
{itemIcon(e.item.effect_type)}
</span>
<span className="aeb-pill-label">
{e.item.name}
{e.item.effect_type === "xp_boost" && e.item.effect_value
? ` ×${e.item.effect_value}`
: ""}
</span>
<span className="aeb-pill-time">
{formatTimeLeft(e.expires_at)}
</span>
</div>
))}
</div>
</>
);
};

View File

@ -0,0 +1,609 @@
import { useEffect, useRef, useState, useCallback } from "react";
import { createPortal } from "react-dom";
import { X } from "lucide-react";
import type { InventoryItem, ActiveEffect } from "../types/quest";
import {
useInventoryStore,
getLiveEffects,
formatTimeLeft,
} from "../stores/useInventoryStore";
import { useAuthStore } from "../stores/authStore";
import { api } from "../utils/api";
// ─── Styles ───────────────────────────────────────────────────────────────────
const STYLES = `
@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@600;700;900&family=Nunito:wght@700;800;900&family=Nunito+Sans:wght@400;600;700&display=swap');
/* ══ OVERLAY ══ */
.inv-overlay {
position: fixed; inset: 0; z-index: 60;
background: rgba(2,5,15,0.78);
backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
display: flex; align-items: flex-end; justify-content: center;
animation: invFadeIn 0.2s ease both;
}
@keyframes invFadeIn { from{opacity:0} to{opacity:1} }
/* ══ SHEET ══ */
.inv-sheet {
width: 100%; max-width: 540px;
background: linear-gradient(180deg, #08111f 0%, #050d1a 100%);
border-radius: 28px 28px 0 0;
border-top: 1.5px solid rgba(251,191,36,0.25);
box-shadow:
0 -16px 60px rgba(0,0,0,0.7),
inset 0 1px 0 rgba(255,255,255,0.06);
overflow: hidden;
display: flex; flex-direction: column;
max-height: 88vh;
animation: invSlideUp 0.38s cubic-bezier(0.34,1.56,0.64,1) both;
position: relative;
}
@keyframes invSlideUp {
from { transform: translateY(100%); opacity:0; }
to { transform: translateY(0); opacity:1; }
}
.inv-sheet::before {
content: '';
position: absolute; inset: 0; pointer-events: none; z-index: 0;
background:
repeating-linear-gradient(110deg, transparent 60%, rgba(56,189,248,0.015) 61%, transparent 62%),
repeating-linear-gradient(70deg, transparent 72%, rgba(56,189,248,0.01) 73%, transparent 74%);
background-size: 300% 300%, 240% 240%;
animation: invSeaSway 16s ease-in-out infinite alternate;
}
@keyframes invSeaSway {
0% { background-position: 0% 0%, 100% 0%; }
100% { background-position: 100% 100%, 0% 100%; }
}
.inv-sheet::after {
content: '';
position: absolute; top: -60px; right: -40px; z-index: 0;
width: 220px; height: 220px; border-radius: 50%;
background: radial-gradient(circle, rgba(251,191,36,0.07), transparent 68%);
pointer-events: none;
}
.inv-handle-row {
display: flex; justify-content: center;
padding: 0.75rem 0 0; flex-shrink: 0; position: relative; z-index: 2;
}
.inv-handle {
width: 40px; height: 4px; border-radius: 100px;
background: rgba(255,255,255,0.1);
}
.inv-header {
position: relative; z-index: 2;
display: flex; align-items: center; justify-content: space-between;
padding: 0.85rem 1.3rem 0;
}
.inv-header-left { display: flex; flex-direction: column; gap: 0.1rem; }
.inv-eyebrow {
font-family: 'Cinzel', serif;
font-size: 0.5rem; font-weight: 700; letter-spacing: 0.22em;
text-transform: uppercase; color: rgba(251,191,36,0.55);
}
.inv-title {
font-family: 'Cinzel', serif;
font-size: 1.28rem; font-weight: 900; color: #fff;
letter-spacing: 0.03em;
text-shadow: 0 0 24px rgba(251,191,36,0.3);
}
.inv-close {
width: 32px; height: 32px; border-radius: 50%;
border: 1.5px solid rgba(255,255,255,0.1);
background: rgba(255,255,255,0.05);
display: flex; align-items: center; justify-content: center;
cursor: pointer; transition: all 0.15s;
flex-shrink: 0;
}
.inv-close:hover {
border-color: rgba(251,191,36,0.5);
background: rgba(251,191,36,0.1);
}
.inv-active-bar {
position: relative; z-index: 2;
display: flex; gap: 0.5rem; overflow-x: auto; scrollbar-width: none;
padding: 0.75rem 1.3rem 0;
}
.inv-active-bar::-webkit-scrollbar { display: none; }
.inv-active-pill {
display: flex; align-items: center; gap: 0.4rem;
flex-shrink: 0;
padding: 0.35rem 0.75rem;
border-radius: 100px;
border: 1.5px solid rgba(251,191,36,0.35);
background: rgba(251,191,36,0.08);
animation: invPillGlow 2.4s ease-in-out infinite;
}
@keyframes invPillGlow {
0%,100% { box-shadow: 0 0 0 0 rgba(251,191,36,0); }
50% { box-shadow: 0 0 12px 2px rgba(251,191,36,0.18); }
}
.inv-active-pill-icon { font-size: 0.9rem; }
.inv-active-pill-name {
font-family: 'Nunito', sans-serif;
font-size: 0.72rem; font-weight: 900; color: #fbbf24;
}
.inv-active-pill-time {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.6rem; font-weight: 700;
color: rgba(251,191,36,0.5);
margin-left: 0.1rem;
}
.inv-divider {
position: relative; z-index: 2;
height: 1px; margin: 0.85rem 1.3rem 0;
background: rgba(255,255,255,0.06);
}
.inv-section-label {
position: relative; z-index: 2;
padding: 0.7rem 1.3rem 0.35rem;
font-family: 'Cinzel', serif;
font-size: 0.48rem; font-weight: 700; letter-spacing: 0.2em;
text-transform: uppercase; color: rgba(255,255,255,0.25);
}
.inv-scroll {
position: relative; z-index: 2;
flex: 1; overflow-y: auto; scrollbar-width: none;
padding: 0 1.1rem calc(1.5rem + env(safe-area-inset-bottom));
}
.inv-scroll::-webkit-scrollbar { display: none; }
.inv-empty {
display: flex; flex-direction: column; align-items: center;
justify-content: center; gap: 0.6rem;
padding: 3rem 1rem;
font-family: 'Nunito', sans-serif;
font-size: 0.85rem; font-weight: 800;
color: rgba(255,255,255,0.25);
}
.inv-empty-icon { font-size: 2.5rem; opacity: 0.4; }
.inv-skeleton-grid {
display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem;
}
.inv-skeleton-card {
height: 140px; border-radius: 20px;
background: rgba(255,255,255,0.04);
animation: invSkel 1.6s ease-in-out infinite;
}
@keyframes invSkel {
0%,100% { opacity: 0.6; }
50% { opacity: 1; }
}
.inv-grid {
display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem;
}
.inv-card {
border-radius: 20px; padding: 1rem;
border: 1.5px solid rgba(255,255,255,0.07);
background: rgba(255,255,255,0.03);
display: flex; flex-direction: column; gap: 0.6rem;
cursor: pointer; position: relative; overflow: hidden;
transition: border-color 0.2s, background 0.2s, transform 0.15s;
animation: invCardIn 0.4s cubic-bezier(0.34,1.56,0.64,1) both;
animation-delay: var(--ci-delay, 0s);
}
@keyframes invCardIn {
from { opacity:0; transform: translateY(14px) scale(0.95); }
to { opacity:1; transform: translateY(0) scale(1); }
}
.inv-card:hover {
border-color: rgba(255,255,255,0.14);
background: rgba(255,255,255,0.06);
transform: translateY(-2px);
}
.inv-card:active { transform: translateY(0) scale(0.98); }
.inv-card.is-active {
border-color: rgba(251,191,36,0.4);
background: rgba(251,191,36,0.06);
}
.inv-card.is-active:hover {
border-color: rgba(251,191,36,0.6);
background: rgba(251,191,36,0.09);
}
@keyframes invActivateFlash {
0% { background: rgba(251,191,36,0.25); border-color: rgba(251,191,36,0.8); }
100%{ background: rgba(251,191,36,0.06); border-color: rgba(251,191,36,0.4); }
}
.inv-card.just-activated { animation: invActivateFlash 0.9s ease forwards; }
.inv-card-sheen {
position: absolute; inset: 0; pointer-events: none;
background: linear-gradient(135deg, transparent 30%, rgba(255,255,255,0.04) 50%, transparent 70%);
transform: translateX(-100%); transition: transform 0.5s ease;
}
.inv-card:hover .inv-card-sheen { transform: translateX(100%); }
.inv-card-icon-wrap {
width: 44px; height: 44px; border-radius: 14px;
display: flex; align-items: center; justify-content: center;
font-size: 1.4rem;
background: rgba(255,255,255,0.06);
border: 1px solid rgba(255,255,255,0.08);
flex-shrink: 0; position: relative;
}
.inv-card.is-active .inv-card-icon-wrap {
background: rgba(251,191,36,0.12);
border-color: rgba(251,191,36,0.3);
}
.inv-card-active-dot {
position: absolute; top: -3px; right: -3px;
width: 10px; height: 10px; border-radius: 50%;
background: #fbbf24; border: 2px solid #08111f;
animation: invDotPulse 2s ease-in-out infinite;
}
@keyframes invDotPulse {
0%,100% { box-shadow: 0 0 0 0 rgba(251,191,36,0.6); }
50% { box-shadow: 0 0 0 5px rgba(251,191,36,0); }
}
.inv-card-name {
font-family: 'Nunito', sans-serif;
font-size: 0.82rem; font-weight: 900; color: #fff; line-height: 1.2;
}
.inv-card.is-active .inv-card-name { color: #fbbf24; }
.inv-card-desc {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.63rem; font-weight: 600;
color: rgba(255,255,255,0.38); line-height: 1.4; flex: 1;
}
.inv-card-meta {
display: flex; align-items: center; justify-content: space-between;
gap: 0.4rem; margin-top: auto;
}
.inv-card-qty {
font-family: 'Nunito', sans-serif;
font-size: 0.65rem; font-weight: 900;
color: rgba(255,255,255,0.3);
background: rgba(255,255,255,0.05);
border-radius: 100px; padding: 0.15rem 0.45rem;
}
.inv-card-type {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.56rem; font-weight: 700;
letter-spacing: 0.1em; text-transform: uppercase;
color: rgba(255,255,255,0.22);
}
.inv-activate-btn {
width: 100%; padding: 0.48rem;
border-radius: 10px; border: none; cursor: pointer;
font-family: 'Nunito', sans-serif;
font-size: 0.7rem; font-weight: 900;
transition: all 0.15s ease;
display: flex; align-items: center; justify-content: center; gap: 0.3rem;
}
.inv-activate-btn.idle {
background: rgba(255,255,255,0.07);
border: 1px solid rgba(255,255,255,0.1);
color: rgba(255,255,255,0.6);
}
.inv-activate-btn.idle:hover { background: rgba(255,255,255,0.12); color: white; }
.inv-activate-btn.activating {
background: rgba(251,191,36,0.1);
border: 1px solid rgba(251,191,36,0.25);
color: rgba(251,191,36,0.6);
cursor: not-allowed;
animation: invSpinLabel 0.4s ease infinite alternate;
}
@keyframes invSpinLabel { from{opacity:0.5} to{opacity:1} }
.inv-activate-btn.active-state {
background: rgba(251,191,36,0.12);
border: 1px solid rgba(251,191,36,0.3);
color: #fbbf24; cursor: default;
}
.inv-activate-btn.success-flash {
background: rgba(74,222,128,0.18);
border: 1px solid rgba(74,222,128,0.4);
color: #4ade80;
animation: invSuccessScale 0.35s cubic-bezier(0.34,1.56,0.64,1) both;
}
@keyframes invSuccessScale { from{transform:scale(0.94)} to{transform:scale(1)} }
.inv-activate-btn:disabled { pointer-events: none; }
.inv-active-time {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.55rem; font-weight: 700; color: rgba(251,191,36,0.5);
}
.inv-toast {
position: fixed; bottom: calc(1.5rem + env(safe-area-inset-bottom));
left: 50%; transform: translateX(-50%);
z-index: 9999;
display: flex; align-items: center; gap: 0.55rem;
padding: 0.7rem 1.2rem;
background: linear-gradient(135deg, #1a3a1a, #0d2010);
border: 1.5px solid rgba(74,222,128,0.45);
border-radius: 100px;
box-shadow: 0 4px 24px rgba(0,0,0,0.5), 0 0 20px rgba(74,222,128,0.12);
font-family: 'Nunito', sans-serif;
font-size: 0.8rem; font-weight: 900; color: #4ade80;
white-space: nowrap;
animation: invToastIn 0.4s cubic-bezier(0.34,1.56,0.64,1) both,
invToastOut 0.3s 2.7s ease forwards;
}
@keyframes invToastIn { from{opacity:0; transform:translateX(-50%) translateY(20px) scale(0.9)} to{opacity:1; transform:translateX(-50%) translateY(0) scale(1)} }
@keyframes invToastOut { from{opacity:1} to{opacity:0; transform:translateX(-50%) translateY(8px)} }
`;
// ─── Item metadata ─────────────────────────────────────────────────────────────
const ITEM_ICON: Record<string, string> = {
xp_boost: "⚡",
streak_shield: "🛡️",
title: "🏴‍☠️",
coin_boost: "🪙",
};
function itemIcon(effectType: string): string {
return ITEM_ICON[effectType] ?? "📦";
}
function isItemActive(
item: InventoryItem,
activeEffects: ActiveEffect[],
): ActiveEffect | null {
const now = Date.now();
return (
activeEffects.find(
(e) =>
e.item.id === item.item.id && new Date(e.expires_at).getTime() > now,
) ?? null
);
}
// ─── Item card ────────────────────────────────────────────────────────────────
const ItemCard = ({
inv,
activeEffects,
activatingId,
lastActivatedId,
onActivate,
index,
}: {
inv: InventoryItem;
activeEffects: ActiveEffect[];
activatingId: string | null;
lastActivatedId: string | null;
onActivate: (id: string) => void;
index: number;
}) => {
const activeEffect = isItemActive(inv, activeEffects);
const isActive = !!activeEffect;
const isActivating = activatingId === inv.id;
const justActivated = lastActivatedId === inv.id;
let btnState: "idle" | "activating" | "active-state" | "success-flash" =
"idle";
if (justActivated) btnState = "success-flash";
else if (isActivating) btnState = "activating";
else if (isActive) btnState = "active-state";
let btnLabel = "Use Item";
if (btnState === "activating") btnLabel = "Activating…";
else if (btnState === "success-flash") btnLabel = "✓ Activated!";
else if (btnState === "active-state") btnLabel = "✓ Active";
return (
<div
className={`inv-card${isActive ? " is-active" : ""}${justActivated ? " just-activated" : ""}`}
style={{ "--ci-delay": `${index * 0.045}s` } as React.CSSProperties}
>
<div className="inv-card-sheen" />
<div className="inv-card-icon-wrap">
{itemIcon(inv.item.effect_type)}
{isActive && <div className="inv-card-active-dot" />}
</div>
<p className="inv-card-name">{inv.item.name}</p>
<p className="inv-card-desc">{inv.item.description}</p>
<div className="inv-card-meta">
<span className="inv-card-qty">×{inv.quantity}</span>
<span className="inv-card-type">
{inv.item.type.replace(/_/g, " ")}
</span>
</div>
{isActive && activeEffect && (
<div className="inv-active-time">
{formatTimeLeft(activeEffect.expires_at)} remaining
</div>
)}
<button
className={`inv-activate-btn ${btnState}`}
onClick={() => !isActive && !isActivating && onActivate(inv.id)}
disabled={isActive || isActivating}
>
{btnLabel}
</button>
</div>
);
};
// ─── Main component ───────────────────────────────────────────────────────────
interface Props {
onClose: () => void;
}
export const InventoryModal = ({ onClose }: Props) => {
const token = useAuthStore((s) => s.token);
const items = useInventoryStore((s) => s.items);
const activeEffects = useInventoryStore((s) => s.activeEffects);
const loading = useInventoryStore((s) => s.loading);
const activatingId = useInventoryStore((s) => s.activatingId);
const lastActivatedId = useInventoryStore((s) => s.lastActivatedId);
const error = useInventoryStore((s) => s.error);
const syncFromAPI = useInventoryStore((s) => s.syncFromAPI);
const setLoading = useInventoryStore((s) => s.setLoading);
const activateItemOptimistic = useInventoryStore(
(s) => s.activateItemOptimistic,
);
const activateItemSuccess = useInventoryStore((s) => s.activateItemSuccess);
const activateItemError = useInventoryStore((s) => s.activateItemError);
const clearLastActivated = useInventoryStore((s) => s.clearLastActivated);
const [showToast, setShowToast] = useState(false);
const [toastMsg, setToastMsg] = useState("");
const toastTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
if (!token) return;
let cancelled = false;
const fetchInv = async () => {
setLoading(true);
try {
const inv = await api.fetchUserInventory(token);
if (!cancelled) syncFromAPI(inv);
} catch (e) {
// Silently fail — cached data stays visible
} finally {
if (!cancelled) setLoading(false);
}
};
fetchInv();
return () => {
cancelled = true;
};
}, [token]);
const handleActivate = useCallback(
async (itemId: string) => {
if (!token) return;
activateItemOptimistic(itemId);
try {
const updatedInv = await api.activateItem(token, itemId);
activateItemSuccess(updatedInv, itemId);
const name = items.find((i) => i.id === itemId)?.item.name ?? "Item";
setToastMsg(
`${itemIcon(items.find((i) => i.id === itemId)?.item.effect_type ?? "")} ${name} activated!`,
);
setShowToast(true);
if (toastTimer.current) clearTimeout(toastTimer.current);
toastTimer.current = setTimeout(() => {
setShowToast(false);
clearLastActivated();
}, 3000);
} catch (e) {
activateItemError(
itemId,
e instanceof Error ? e.message : "Failed to activate",
);
}
},
[token, items],
);
useEffect(
() => () => {
if (toastTimer.current) clearTimeout(toastTimer.current);
},
[],
);
const liveEffects = getLiveEffects(activeEffects);
// Portal the entire modal to document.body so it always
// renders at the top of the DOM tree, escaping any parent
// stacking context, overflow:hidden, or z-index constraints.
return createPortal(
<>
<style>{STYLES}</style>
<div className="inv-overlay" onClick={onClose}>
<div className="inv-sheet" onClick={(e) => e.stopPropagation()}>
<div className="inv-handle-row">
<div className="inv-handle" />
</div>
<div className="inv-header">
<div className="inv-header-left">
<span className="inv-eyebrow"> Pirate's Hold</span>
<h2 className="inv-title">Inventory</h2>
</div>
<button className="inv-close" onClick={onClose}>
<X size={14} color="rgba(255,255,255,0.5)" />
</button>
</div>
{liveEffects.length > 0 && (
<div className="inv-active-bar">
{liveEffects.map((e) => (
<div key={e.id} className="inv-active-pill">
<span className="inv-active-pill-icon">
{itemIcon(e.item.effect_type)}
</span>
<span className="inv-active-pill-name">{e.item.name}</span>
<span className="inv-active-pill-time">
{formatTimeLeft(e.expires_at)}
</span>
</div>
))}
</div>
)}
<div className="inv-divider" />
<p className="inv-section-label">
{items.length > 0
? `${items.length} item${items.length !== 1 ? "s" : ""} in your hold`
: "Your hold"}
</p>
<div className="inv-scroll">
{loading && items.length === 0 ? (
<div className="inv-skeleton-grid">
{[0, 1, 2, 3].map((i) => (
<div
key={i}
className="inv-skeleton-card"
style={{ animationDelay: `${i * 0.1}s` }}
/>
))}
</div>
) : items.length === 0 ? (
<div className="inv-empty">
<span className="inv-empty-icon">🏴‍☠️</span>
<p>Your hold is empty — claim quests to earn items!</p>
</div>
) : (
<div className="inv-grid">
{items.map((inv, i) => (
<ItemCard
key={inv.id}
inv={inv}
activeEffects={activeEffects}
activatingId={activatingId}
lastActivatedId={lastActivatedId}
onActivate={handleActivate}
index={i}
/>
))}
</div>
)}
{error && (
<p
style={{
textAlign: "center",
padding: "0.5rem",
fontFamily: "'Nunito',sans-serif",
fontSize: "0.72rem",
color: "#ef4444",
fontWeight: 800,
}}
>
⚠️ {error}
</p>
)}
</div>
</div>
</div>
{showToast && <div className="inv-toast">{toastMsg}</div>}
</>,
document.body,
);
};

View File

@ -1,8 +1,16 @@
import { useEffect, useState } from "react";
import { Dialog, DialogContent, DialogHeader } from "../components/ui/dialog";
import { useEffect, useRef, useState, Suspense } from "react";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "../components/ui/dialog";
import { api } from "../utils/api";
import { useAuthStore } from "../stores/authStore";
import { Loader, X } from "lucide-react";
import { LESSON_COMPONENT_MAP } from "./FetchLessonPage";
import type { LessonId } from "./FetchLessonPage";
import type { LessonDetails } from "../types/lesson";
interface LessonModalProps {
lessonId: string | null;
@ -10,10 +18,22 @@ interface LessonModalProps {
onOpenChange: (open: boolean) => void;
}
// UUIDs are video lessons; local lessons use readable keys like "ebrw-main-idea"
const UUID_REGEX =
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
const isVideoLesson = (id: string) => UUID_REGEX.test(id);
function getLocalLessonTitle(lessonId: string): string {
const comp = LESSON_COMPONENT_MAP[lessonId as LessonId] as any;
if (comp?.displayName) return comp.displayName;
return lessonId
.replace(/[-_]/g, " ")
.replace(/\b\w/g, (c) => c.toUpperCase());
}
const STYLES = `
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@400;700;800;900&family=Nunito+Sans:wght@400;600;700&display=swap');
/* Override Dialog defaults */
.lm-content {
font-family: 'Nunito', sans-serif;
background: #fffbf4;
@ -28,15 +48,16 @@ const STYLES = `
display: flex;
flex-direction: column;
}
/* Header bar */
.lm-dialog-header-hidden {
position: absolute; width: 1px; height: 1px;
padding: 0; margin: -1px; overflow: hidden;
clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.lm-header {
display: flex; align-items: flex-start; justify-content: space-between;
padding: 1.25rem 1.5rem 0;
flex-shrink: 0;
gap: 1rem;
padding: 1.25rem 1.5rem 0; flex-shrink: 0; gap: 1rem;
}
.lm-title-wrap { display:flex;flex-direction:column;gap:0.2rem; flex:1; }
.lm-title-wrap { display:flex; flex-direction:column; gap:0.2rem; flex:1; }
.lm-eyebrow {
font-size: 0.62rem; font-weight: 800; letter-spacing: 0.16em;
text-transform: uppercase; color: #a855f7;
@ -50,38 +71,26 @@ const STYLES = `
border-radius: 50%; border: 2.5px solid #f3f4f6;
background: white; cursor: pointer;
display: flex; align-items: center; justify-content: center;
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
transition: all 0.15s ease;
box-shadow: 0 2px 8px rgba(0,0,0,0.06); transition: all 0.15s ease;
}
.lm-close-btn:hover { border-color: #fecdd3; background: #fff1f2; }
/* Scrollable body */
.lm-body {
overflow-y: auto;
flex: 1;
overflow-y: auto; flex: 1;
padding: 1rem 1.5rem 1.5rem;
display: flex; flex-direction: column; gap: 1rem;
-webkit-overflow-scrolling: touch;
}
/* Video player */
.lm-video {
width: 100%; border-radius: 18px;
aspect-ratio: 16/9; background: #1e1b4b;
display: block;
aspect-ratio: 16/9; background: #1e1b4b; display: block;
}
/* Topic chip */
.lm-topic-chip {
display: inline-flex; align-items: center; gap: 0.4rem;
background: #f3e8ff; border: 2px solid #e9d5ff;
border-radius: 100px; padding: 0.3rem 0.8rem;
font-size: 0.7rem; font-weight: 800;
letter-spacing: 0.08em; text-transform: uppercase;
color: #9333ea; width: fit-content;
font-size: 0.7rem; font-weight: 800; letter-spacing: 0.08em;
text-transform: uppercase; color: #9333ea; width: fit-content;
}
/* Description & content cards */
.lm-card {
background: white; border: 2.5px solid #f3f4f6;
border-radius: 18px; padding: 1rem 1.1rem;
@ -93,88 +102,175 @@ const STYLES = `
}
.lm-card-text {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.88rem; font-weight: 600; color: #374151;
line-height: 1.6;
font-size: 0.88rem; font-weight: 600; color: #374151; line-height: 1.6;
}
/* Loading state */
.lm-loading {
display: flex; flex-direction: column; align-items: center;
justify-content: center; gap: 0.75rem;
padding: 3rem 1.5rem;
flex: 1;
justify-content: center; gap: 0.75rem; padding: 3rem 1.5rem; flex: 1;
}
.lm-loading-spinner { animation: lmSpin 0.8s linear infinite; }
@keyframes lmSpin { to { transform: rotate(360deg); } }
.lm-loading-text {
font-size: 0.85rem; font-weight: 700; color: #9ca3af;
.lm-loading-text { font-size: 0.85rem; font-weight: 700; color: #9ca3af; }
.lm-error {
display: flex; flex-direction: column; align-items: center;
justify-content: center; gap: 0.5rem;
padding: 3rem 1.5rem; text-align: center; flex: 1;
}
.lm-error-emoji { font-size: 2rem; }
.lm-error-text { font-size: 0.85rem; font-weight: 700; color: #9ca3af; }
/* Resources list */
.lm-resources { display: flex; flex-direction: column; gap: 0.5rem; }
.lm-resource-link {
display: flex; align-items: center; gap: 0.6rem;
padding: 0.6rem 0.8rem; border-radius: 12px;
background: #f5f3ff; border: 1.5px solid #e9d5ff;
color: #7c3aed; font-size: 0.8rem; font-weight: 700;
text-decoration: none; transition: background 0.15s ease;
}
.lm-resource-link:hover { background: #ede9fe; }
/* Creator badge */
.lm-creator {
display: flex; align-items: center; gap: 0.5rem;
font-family: 'Nunito Sans', sans-serif;
font-size: 0.75rem; font-weight: 600; color: #9ca3af;
}
.lm-creator-avatar {
width: 24px; height: 24px; border-radius: 50%;
background: linear-gradient(135deg, #a855f7, #3b82f6);
display: flex; align-items: center; justify-content: center;
font-size: 0.65rem; font-weight: 900; color: white; flex-shrink: 0;
}
`;
const LoadingSpinner = () => (
<div className="lm-loading">
<Loader size={28} color="#a855f7" className="lm-loading-spinner" />
<p className="lm-loading-text">Loading lesson...</p>
</div>
);
export const LessonModal = ({
lessonId,
open,
onOpenChange,
}: LessonModalProps) => {
const user = useAuthStore((state) => state.user);
const [loading, setLoading] = useState(false);
const [lesson, setLesson] = useState<any>(null);
const [lesson, setLesson] = useState<LessonDetails | null>(null);
const [error, setError] = useState(false);
const fetchingForId = useRef<string | null>(null);
const LocalLessonComponent =
lessonId && !isVideoLesson(lessonId)
? LESSON_COMPONENT_MAP[lessonId as LessonId]
: null;
const modalTitle = LocalLessonComponent
? getLocalLessonTitle(lessonId!)
: loading
? "Loading..."
: (lesson?.title ?? "Lesson");
useEffect(() => {
if (!open || !lessonId || !user) return;
if (!open) {
setLesson(null);
setLoading(false);
setError(false);
fetchingForId.current = null;
return;
}
if (!lessonId || !user || LocalLessonComponent) return;
if (fetchingForId.current === lessonId) return;
const fetchLesson = async () => {
try {
fetchingForId.current = lessonId;
setLesson(null);
setError(false);
setLoading(true);
try {
const authStorage = localStorage.getItem("auth-storage");
if (!authStorage) return;
if (!authStorage) throw new Error("No auth storage");
const {
state: { token },
} = JSON.parse(authStorage) as { state?: { token?: string } };
if (!token) return;
const response = await api.fetchLessonById(token, lessonId);
if (!token) throw new Error("No token");
// fetchLessonById returns LessonDetails directly
const response: LessonDetails = await api.fetchLessonById(
token,
lessonId,
);
if (fetchingForId.current !== lessonId) return;
setLesson(response);
} catch (err) {
console.error("Failed to fetch lesson", err);
if (fetchingForId.current === lessonId) setError(true);
} finally {
setLoading(false);
if (fetchingForId.current === lessonId) setLoading(false);
}
};
fetchLesson();
}, [open, lessonId, user]);
}, [open, lessonId, user, LocalLessonComponent]);
// topic on LessonDetails is Topic[] — use the first entry
const topicName = Array.isArray(lesson?.topic)
? lesson.topic[0]?.name
: ((lesson?.topic as any)?.name ?? null);
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<style>{STYLES}</style>
<DialogContent className="lm-content" showCloseButton={false}>
<DialogHeader style={{ display: "none" }} />
<DialogHeader className="lm-dialog-header-hidden">
<DialogTitle>{modalTitle}</DialogTitle>
</DialogHeader>
{/* Header */}
<div className="lm-header">
<div className="lm-title-wrap">
<span className="lm-eyebrow">📖 Lesson</span>
<h2 className="lm-title">
{loading ? "Loading..." : (lesson?.title ?? "Lesson details")}
</h2>
<h2 className="lm-title">{modalTitle}</h2>
</div>
<button className="lm-close-btn" onClick={() => onOpenChange(false)}>
<X size={16} color="#6b7280" />
</button>
</div>
{/* Body */}
{loading ? (
<div className="lm-loading">
<Loader size={28} color="#a855f7" className="lm-loading-spinner" />
<p className="lm-loading-text">Loading lesson...</p>
<LoadingSpinner />
) : error ? (
<div className="lm-error">
<span className="lm-error-emoji">😕</span>
<p className="lm-error-text">
Couldn't load this lesson. Please try again.
</p>
</div>
) : (
lesson && (
<div className="lm-body">
{LocalLessonComponent ? (
<Suspense fallback={<LoadingSpinner />}>
<LocalLessonComponent />
</Suspense>
) : (
lesson && (
<>
{/* Video */}
{lesson.video_url && (
<video src={lesson.video_url} controls className="lm-video" />
<video
src={lesson.video_url}
controls
className="lm-video"
/>
)}
{lesson.topic?.name && (
{/* Topic chip */}
{topicName && (
<div>
<span className="lm-topic-chip">
<span
@ -186,11 +282,12 @@ export const LessonModal = ({
flexShrink: 0,
}}
/>
{lesson.topic.name}
{topicName}
</span>
</div>
)}
{/* Description */}
{lesson.description && (
<div className="lm-card">
<p className="lm-card-label">About this lesson</p>
@ -198,15 +295,48 @@ export const LessonModal = ({
</div>
)}
{/* Content */}
{lesson.content && (
<div className="lm-card">
<p className="lm-card-label">Content</p>
<p className="lm-card-text">{lesson.content}</p>
</div>
)}
{/* Resources */}
{lesson.resources && lesson.resources.length > 0 && (
<div className="lm-card">
<p className="lm-card-label">Resources</p>
<div className="lm-resources">
{lesson.resources.map((r: any, i: number) => (
<a
key={i}
href={r.url ?? r.link ?? "#"}
target="_blank"
rel="noopener noreferrer"
className="lm-resource-link"
>
📎 {r.title ?? r.name ?? `Resource ${i + 1}`}
</a>
))}
</div>
</div>
)}
{/* Created by */}
{lesson.created_by?.name && (
<div className="lm-creator">
<div className="lm-creator-avatar">
{lesson.created_by.name.charAt(0).toUpperCase()}
</div>
Lesson by {lesson.created_by.name}
</div>
)}
</>
)
)}
</div>
)}
</DialogContent>
</Dialog>
);

View File

@ -0,0 +1,93 @@
import { useEffect, useState } from "react";
import { useAuthStore } from "../stores/authStore";
const STYLES = `
.lb-wrap {
display: flex; align-items: center; gap: 0.55rem;
background: white;
border: 2px solid #f3f4f6;
border-radius: 100px;
padding: 0.38rem 0.75rem 0.38rem 0.42rem;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
animation: lbIn 0.4s cubic-bezier(0.34,1.56,0.64,1) both;
}
@keyframes lbIn {
from { opacity:0; transform: scale(0.9) translateX(6px); }
to { opacity:1; transform: scale(1) translateX(0); }
}
/* Level bubble */
.lb-bubble {
width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0;
background: linear-gradient(135deg, #a855f7, #7c3aed);
display: flex; align-items: center; justify-content: center;
box-shadow: 0 2px 0 #5b21b644;
font-family: 'Nunito', sans-serif;
font-size: 0.7rem; font-weight: 900; color: white;
letter-spacing: -0.02em;
}
/* Bar track */
.lb-track {
width: 80px; height: 7px;
background: #f3f4f6; border-radius: 100px; overflow: hidden;
flex-shrink: 0;
}
.lb-fill {
height: 100%; border-radius: 100px;
background: linear-gradient(90deg, #a855f7, #f97316);
transition: width 1s cubic-bezier(0.34,1.56,0.64,1);
position: relative; overflow: hidden;
}
.lb-fill::after {
content: '';
position: absolute; inset: 0;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.45), transparent);
transform: translateX(-100%);
animation: lbShimmer 2.2s ease-in-out 1s infinite;
}
@keyframes lbShimmer { to { transform: translateX(200%); } }
/* XP label */
.lb-label {
font-family: 'Nunito', sans-serif;
font-size: 0.68rem; font-weight: 900;
color: #a855f7; white-space: nowrap;
}
`;
export const LevelBar = () => {
const user = useAuthStore((s) => s.user);
const u = user as any;
const level = u?.current_level ?? u?.level ?? 1;
const totalXP = u?.total_xp ?? u?.xp ?? 0;
const levelStart = u?.current_level_start ?? u?.level_min_xp ?? 0;
const levelEnd =
u?.next_level_threshold ?? u?.level_max_xp ?? levelStart + 1000;
const levelRange = Math.max(levelEnd - levelStart, 1);
const xpIntoLevel = Math.max(totalXP - levelStart, 0);
const rawPct = Math.min(Math.round((xpIntoLevel / levelRange) * 100), 100);
const [pct, setPct] = useState(0);
useEffect(() => {
const id = requestAnimationFrame(() =>
requestAnimationFrame(() => setPct(rawPct)),
);
return () => cancelAnimationFrame(id);
}, [rawPct]);
return (
<>
<style>{STYLES}</style>
<div className="lb-wrap">
<div className="lb-bubble">{level}</div>
<div className="lb-track">
<div className="lb-fill" style={{ width: `${pct}%` }} />
</div>
<span className="lb-label">{pct}%</span>
</div>
</>
);
};

25
src/components/Math.tsx Normal file
View File

@ -0,0 +1,25 @@
import React from "react";
/**
* Renders a proper stacked fraction with numerator above denominator.
* Usage: <Frac n="x² 1" d="x² 2x + 1" />
*/
export const Frac = ({ n, d }: { n: React.ReactNode; d: React.ReactNode }) => (
<span
style={{
display: "inline-flex",
flexDirection: "column",
alignItems: "center",
verticalAlign: "middle",
lineHeight: 1.25,
margin: "0 3px",
}}
>
<span
style={{ borderBottom: "1.5px solid currentColor", padding: "0 4px 2px" }}
>
{n}
</span>
<span style={{ padding: "2px 4px 0" }}>{d}</span>
</span>
);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,507 @@
import { useState } from "react";
import { ChevronDown, ChevronRight } from "lucide-react";
import { useNavigate } from "react-router-dom";
import type { QuestNode, QuestArc } from "../types/quest";
import { CREW_RANKS } from "../types/quest";
import {
useQuestStore,
getQuestSummary,
getCrewRank,
} from "../stores/useQuestStore";
import { ChestOpenModal } from "./ChestOpenModal";
// ─── Styles ───────────────────────────────────────────────────────────────────
const STYLES = `
@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@600;700;900&family=Sorts+Mill+Goudy:ital@0;1&family=Nunito:wght@700;800;900&family=Nunito+Sans:wght@400;600;700&display=swap');
/* ══ CARD SHELL ══ */
.qpc2-card {
position: relative; overflow: hidden;
border-radius: 24px;
background: linear-gradient(160deg, #0b1a35 0%, #060e1f 55%, #0d1530 100%);
border: 1.5px solid rgba(251,191,36,0.2);
box-shadow:
0 8px 32px rgba(0,0,0,0.35),
0 0 0 1px rgba(255,255,255,0.04) inset,
0 1px 0 rgba(255,255,255,0.08) inset;
}
/* Animated sea shimmer behind everything */
.qpc2-sea {
position: absolute; inset: 0; pointer-events: none; z-index: 0;
background:
repeating-linear-gradient(105deg, transparent 0%, transparent 55%,
rgba(56,189,248,0.022) 56%, transparent 57%),
repeating-linear-gradient(75deg, transparent 0%, transparent 70%,
rgba(56,189,248,0.014) 71%, transparent 72%);
background-size: 300% 300%, 250% 250%;
animation: qpc2Sea 12s ease-in-out infinite alternate;
}
@keyframes qpc2Sea {
0% { background-position: 0% 0%, 100% 0%; }
100% { background-position: 100% 100%, 0% 100%; }
}
/* Faint gold orb top-right */
.qpc2-orb {
position: absolute; top: -40px; right: -30px;
width: 160px; height: 160px; border-radius: 50%;
background: radial-gradient(circle, rgba(251,191,36,0.14) 0%, transparent 70%);
pointer-events: none; z-index: 0;
}
/* ══ RANK HERO (always visible) ══ */
.qpc2-hero {
position: relative; z-index: 2;
padding: 1rem 1.1rem 0.9rem;
cursor: pointer;
transition: background 0.18s ease;
}
.qpc2-hero:hover { background: rgba(255,255,255,0.025); }
.qpc2-hero-row {
display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
}
.qpc2-hero-left { display: flex; align-items: center; gap: 0.75rem; flex: 1; min-width: 0; }
.qpc2-hero-right { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
/* Rank badge icon */
.qpc2-rank-icon {
width: 44px; height: 44px; border-radius: 14px; flex-shrink: 0;
background: linear-gradient(135deg, #1e0e4a, #3730a3);
border: 1.5px solid rgba(251,191,36,0.35);
display: flex; align-items: center; justify-content: center;
font-size: 1.35rem;
box-shadow: 0 4px 0 rgba(30,14,74,0.7), 0 0 16px rgba(251,191,36,0.1);
}
.qpc2-rank-label {
font-family: 'Cinzel', serif;
font-size: 0.78rem; font-weight: 700;
color: rgba(255,255,255,0.45); letter-spacing: 0.12em;
text-transform: uppercase; margin-bottom: 0.1rem;
}
.qpc2-rank-name {
font-family: 'Sorts Mill Goudy', serif;
font-size: 1.05rem; font-weight: 700;
color: #fbbf24;
text-shadow: 0 0 18px rgba(251,191,36,0.45);
line-height: 1.1;
}
/* Rank progress bar */
.qpc2-rank-bar-wrap {
margin-top: 0.55rem;
display: flex; align-items: center; gap: 0.6rem;
}
.qpc2-rank-bar-track {
flex: 1; height: 5px; border-radius: 100px;
background: rgba(255,255,255,0.1); overflow: hidden;
}
.qpc2-rank-bar-fill {
height: 100%; border-radius: 100px;
background: linear-gradient(90deg, #fbbf24, #f59e0b);
box-shadow: 0 0 8px rgba(251,191,36,0.5);
transition: width 0.7s cubic-bezier(0.34,1.56,0.64,1);
}
.qpc2-rank-bar-label {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.6rem; font-weight: 700;
color: rgba(255,255,255,0.35); white-space: nowrap;
}
/* Stats row */
.qpc2-stats {
display: flex; gap: 0.5rem; margin-top: 0.75rem;
padding-top: 0.7rem;
border-top: 1px solid rgba(255,255,255,0.07);
}
.qpc2-stat {
flex: 1; display: flex; flex-direction: column; align-items: center; gap: 0.1rem;
}
.qpc2-stat-val {
font-family: 'Nunito', sans-serif;
font-size: 0.95rem; font-weight: 900; color: #fbbf24;
}
.qpc2-stat-lbl {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.56rem; font-weight: 700;
color: rgba(255,255,255,0.35); text-align: center;
letter-spacing: 0.06em; text-transform: uppercase;
}
.qpc2-stat-div {
width: 1px; background: rgba(255,255,255,0.08); margin: 0.1rem 0;
}
/* Chest badge */
.qpc2-chest-badge {
display: flex; align-items: center; gap: 0.22rem;
padding: 0.22rem 0.6rem;
background: linear-gradient(135deg, #fbbf24, #f59e0b);
border-radius: 100px;
font-family: 'Nunito', sans-serif;
font-size: 0.65rem; font-weight: 900; color: #1a0800;
box-shadow: 0 2px 0 #d97706, 0 0 10px rgba(251,191,36,0.35);
animation: qpc2ChestPop 1.8s ease-in-out infinite;
}
@keyframes qpc2ChestPop {
0%,100%{ transform: scale(1); }
50% { transform: scale(1.07); }
}
/* Expand chevron */
.qpc2-chevron {
color: rgba(255,255,255,0.35);
transition: transform 0.3s cubic-bezier(0.34,1.56,0.64,1), color 0.2s;
}
.qpc2-chevron.open { transform: rotate(180deg); color: #fbbf24; }
/* ══ COLLAPSIBLE BODY ══ */
.qpc2-body {
position: relative; z-index: 2;
overflow: hidden;
max-height: 0;
transition: max-height 0.4s cubic-bezier(0.4,0,0.2,1);
}
.qpc2-body.open { max-height: 600px; }
.qpc2-divider {
height: 1px; background: rgba(255,255,255,0.07); margin: 0 1.1rem;
}
/* ══ QUEST ROWS ══ */
.qpc2-quest-list { display: flex; flex-direction: column; padding: 0.5rem 0; }
.qpc2-quest-row {
display: flex; align-items: center; gap: 0.7rem;
padding: 0.75rem 1.1rem;
cursor: pointer;
transition: background 0.15s ease;
position: relative;
}
.qpc2-quest-row:hover { background: rgba(255,255,255,0.03); }
/* Left accent line = arc colour */
.qpc2-quest-row::before {
content: ''; position: absolute; left: 0; top: 16%; bottom: 16%;
width: 3px; border-radius: 0 3px 3px 0;
background: var(--ac);
opacity: 0.7;
}
.qpc2-quest-icon {
width: 38px; height: 38px; border-radius: 12px; flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
font-size: 1.2rem;
background: rgba(255,255,255,0.05);
border: 1.5px solid rgba(255,255,255,0.08);
transition: transform 0.2s ease;
}
.qpc2-quest-row:hover .qpc2-quest-icon { transform: scale(1.1) rotate(-5deg); }
.qpc2-quest-icon.claimable {
background: rgba(251,191,36,0.12);
border-color: rgba(251,191,36,0.4);
animation: qpc2Wiggle 2s ease-in-out infinite;
}
@keyframes qpc2Wiggle {
0%,100%{ transform: rotate(0deg); }
25% { transform: rotate(-8deg) scale(1.06); }
75% { transform: rotate(8deg) scale(1.06); }
}
.qpc2-quest-body { flex: 1; min-width: 0; }
.qpc2-quest-arc {
font-size: 0.57rem; font-weight: 800; letter-spacing: 0.12em;
text-transform: uppercase; color: var(--ac);
margin-bottom: 0.08rem;
}
.qpc2-quest-title {
font-family: 'Sorts Mill Goudy', serif;
font-size: 0.82rem; font-weight: 700; color: rgba(255,255,255,0.9);
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
margin-bottom: 0.28rem;
}
.qpc2-mini-track {
height: 4px; background: rgba(255,255,255,0.08);
border-radius: 100px; overflow: hidden; margin-bottom: 0.18rem;
}
.qpc2-mini-fill {
height: 100%; border-radius: 100px;
background: var(--ac);
box-shadow: 0 0 5px color-mix(in srgb, var(--ac) 55%, transparent);
transition: width 0.5s cubic-bezier(0.34,1.56,0.64,1);
}
.qpc2-mini-label {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.58rem; font-weight: 700; color: rgba(255,255,255,0.3);
}
.qpc2-claimable-label {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.62rem; font-weight: 700; color: #fbbf24;
}
/* Claim button */
.qpc2-claim-btn {
padding: 0.32rem 0.7rem; border: none; border-radius: 100px; cursor: pointer;
background: linear-gradient(135deg, #fbbf24, #f59e0b);
font-family: 'Nunito', sans-serif;
font-size: 0.65rem; font-weight: 900; color: #1a0800;
box-shadow: 0 2px 0 #d97706, 0 3px 8px rgba(251,191,36,0.25);
flex-shrink: 0; white-space: nowrap;
transition: all 0.12s ease;
}
.qpc2-claim-btn:hover { transform: translateY(-1px); box-shadow: 0 3px 0 #d97706; }
.qpc2-claim-btn:active { transform: translateY(1px); }
/* ══ FOOTER LINK ══ */
.qpc2-footer {
position: relative; z-index: 2;
display: flex; align-items: center; justify-content: center; gap: 0.3rem;
padding: 0.65rem 1.1rem;
border-top: 1px solid rgba(255,255,255,0.07);
cursor: pointer;
transition: background 0.15s ease;
}
.qpc2-footer:hover { background: rgba(255,255,255,0.03); }
.qpc2-footer-label {
font-family: 'Nunito', sans-serif;
font-size: 0.72rem; font-weight: 800;
color: rgba(251,191,36,0.7);
letter-spacing: 0.04em;
}
.qpc2-footer:hover .qpc2-footer-label { color: #fbbf24; }
/* ══ EMPTY STATE ══ */
.qpc2-empty {
padding: 1.25rem 1.1rem; text-align: center;
display: flex; flex-direction: column; align-items: center; gap: 0.35rem;
}
.qpc2-empty-title {
font-family: 'Sorts Mill Goudy', serif;
font-size: 0.88rem; font-weight: 700; color: rgba(255,255,255,0.55);
}
.qpc2-empty-sub {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.68rem; font-weight: 600; color: rgba(255,255,255,0.25);
}
`;
// ─── Helpers ──────────────────────────────────────────────────────────────────
function getActiveQuests(arcs: QuestArc[]) {
const results: { node: QuestNode; arc: QuestArc }[] = [];
for (const arc of arcs) {
for (const node of arc.nodes) {
if (node.status === "claimable" || node.status === "active") {
results.push({ node, arc });
}
}
}
// Claimable first, then active; max 2 shown
results.sort((a, b) => {
if (a.node.status === "claimable" && b.node.status !== "claimable")
return -1;
if (b.node.status === "claimable" && a.node.status !== "claimable")
return 1;
return 0;
});
return results.slice(0, 2);
}
// ─── Component ────────────────────────────────────────────────────────────────
interface Props {
onViewAll?: () => void;
}
export const QuestProgressCard = ({ onViewAll }: Props) => {
const navigate = useNavigate();
const arcs = useQuestStore((s) => s.arcs);
const claimNode = useQuestStore((s) => s.claimNode);
const summary = getQuestSummary(arcs);
const rank = getCrewRank(arcs);
const activeQuests = getActiveQuests(arcs);
const [open, setOpen] = useState(false);
const [claimingNode, setClaimingNode] = useState<{
node: QuestNode;
arcId: string;
} | null>(null);
const handleViewAll = () => {
if (onViewAll) onViewAll();
else navigate("/student/quests");
};
const handleClaim = (node: QuestNode, arcId: string) => {
setClaimingNode({ node, arcId });
};
const handleChestClose = () => {
if (!claimingNode) return;
claimNode(claimingNode.arcId, claimingNode.node.id);
setClaimingNode(null);
};
// Next rank label
const nextRankLabel = rank.next
? `${Math.round(rank.progressToNext * 100)}% to ${rank.next.label}`
: "Max rank reached";
return (
<>
<style>{STYLES}</style>
<div className="qpc2-card">
{/* Atmosphere layers */}
<div className="qpc2-sea" />
<div className="qpc2-orb" />
{/* ── Rank hero (always visible, tap to expand) ── */}
<div className="qpc2-hero" onClick={() => setOpen((o) => !o)}>
<div className="qpc2-hero-row">
<div className="qpc2-hero-left">
<div className="qpc2-rank-icon">{rank.emoji}</div>
<div style={{ flex: 1, minWidth: 0 }}>
<p className="qpc2-rank-label">Crew Rank</p>
<p className="qpc2-rank-name">{rank.label}</p>
</div>
</div>
<div className="qpc2-hero-right">
{summary.claimableNodes > 0 && (
<div className="qpc2-chest-badge">
📦 {summary.claimableNodes}
</div>
)}
<ChevronDown
size={18}
className={`qpc2-chevron${open ? " open" : ""}`}
/>
</div>
</div>
{/* Rank progress bar */}
<div className="qpc2-rank-bar-wrap">
<div className="qpc2-rank-bar-track">
<div
className="qpc2-rank-bar-fill"
style={{ width: `${Math.round(rank.progressToNext * 100)}%` }}
/>
</div>
<span className="qpc2-rank-bar-label">{nextRankLabel}</span>
</div>
{/* Stats strip */}
<div className="qpc2-stats">
{[
{ val: `${summary.earnedXP}`, lbl: "XP Earned" },
null,
{
val: `${summary.completedNodes}/${summary.totalNodes}`,
lbl: "Quests Done",
},
null,
{
val: `${summary.arcsCompleted}/${summary.totalArcs}`,
lbl: "Arcs",
},
].map((item, i) =>
item === null ? (
<div key={i} className="qpc2-stat-div" />
) : (
<div key={i} className="qpc2-stat">
<span className="qpc2-stat-val">{item.val}</span>
<span className="qpc2-stat-lbl">{item.lbl}</span>
</div>
),
)}
</div>
</div>
{/* ── Collapsible quest list ── */}
<div className={`qpc2-body${open ? " open" : ""}`}>
<div className="qpc2-divider" />
<div className="qpc2-quest-list">
{activeQuests.length === 0 ? (
<div className="qpc2-empty">
<span style={{ fontSize: "1.75rem" }}></span>
<p className="qpc2-empty-title">All caught up, Captain!</p>
<p className="qpc2-empty-sub">
No active quests keep sailing
</p>
</div>
) : (
activeQuests.map(({ node, arc }) => {
const pct = Math.min(
100,
Math.round((node.progress / node.requirement.target) * 100),
);
const isClaimable = node.status === "claimable";
return (
<div
key={node.id}
className="qpc2-quest-row"
style={{ "--ac": arc.accentColor } as React.CSSProperties}
onClick={() => !isClaimable && handleViewAll()}
>
<div
className={`qpc2-quest-icon${isClaimable ? " claimable" : ""}`}
>
{isClaimable ? "📦" : node.emoji}
</div>
<div className="qpc2-quest-body">
<p className="qpc2-quest-arc">
{arc.emoji} {arc.name}
</p>
<p className="qpc2-quest-title">{node.title}</p>
{isClaimable ? (
<p className="qpc2-claimable-label">
Chest ready to open!
</p>
) : (
<>
<div className="qpc2-mini-track">
<div
className="qpc2-mini-fill"
style={{ width: `${pct}%` }}
/>
</div>
<p className="qpc2-mini-label">
{node.progress} / {node.requirement.target}{" "}
{node.requirement.label}
</p>
</>
)}
</div>
{isClaimable ? (
<button
className="qpc2-claim-btn"
onClick={(e) => {
e.stopPropagation();
handleClaim(node, arc.id);
}}
>
Open 📦
</button>
) : (
<ChevronRight size={14} color="rgba(255,255,255,0.2)" />
)}
</div>
);
})
)}
</div>
{/* Footer — navigate to full map */}
<div className="qpc2-footer" onClick={handleViewAll}>
<span className="qpc2-footer-label">View full quest map</span>
<ChevronRight size={14} color="rgba(251,191,36,0.7)" />
</div>
</div>
</div>
{claimingNode && (
<ChestOpenModal node={claimingNode.node} onClose={handleChestClose} />
)}
</>
);
};

View File

@ -0,0 +1,36 @@
import {
Target,
BookOpen,
BarChart3,
Layers,
Calculator,
TrendingUp,
Grid,
Scale,
Percent,
Car,
Square,
Triangle,
Circle,
} from "lucide-react";
import type { JSX } from "react";
export const renderLessonIcon = (iconName: string) => {
const icons: Record<string, JSX.Element> = {
Target: <Target size={16} />,
BookOpen: <BookOpen size={16} />,
BarChart3: <BarChart3 size={16} />,
Layers: <Layers size={16} />,
Calculator: <Calculator size={16} />,
TrendingUp: <TrendingUp size={16} />,
Grid: <Grid size={16} />,
Scale: <Scale size={16} />,
Percent: <Percent size={16} />,
Chart: <Car size={16} />,
Square: <Square size={16} />,
Triangle: <Triangle size={16} />,
Circle: <Circle size={16} />,
};
return icons[iconName] ?? <BookOpen size={16} />;
};

View File

@ -1,6 +1,18 @@
import { motion, AnimatePresence } from "framer-motion";
import { useEffect, useMemo } from "react";
import { Search, X } from "lucide-react";
import { useEffect, useMemo, useRef, useState } from "react";
import {
Search,
X,
BookOpen,
Zap,
Target,
Trophy,
User,
Home,
ArrowRight,
Clock,
Flame,
} from "lucide-react";
import type { PracticeSheet } from "../types/sheet";
import { useNavigate } from "react-router-dom";
import type { SearchItem } from "../types/search";
@ -13,20 +25,32 @@ interface Props {
setSearchQuery: (value: string) => void;
}
const navigationItems: SearchItem[] = [
// ─── Nav items ────────────────────────────────────────────────────────────────
const NAV_ITEMS: (SearchItem & {
icon: React.ElementType;
color: string;
bg: string;
})[] = [
{
type: "route",
title: "Hard Test Modules",
description: "Access advanced SAT modules",
description: "Tackle the hardest SAT questions",
route: "/student/hard-test-modules",
group: "Pages",
icon: Trophy,
color: "#84cc16",
bg: "#f7ffe4",
},
{
type: "route",
title: "Targeted Practice",
description: "Focus on what matters",
description: "Focus on your weak spots",
route: "/student/practice/targeted-practice",
group: "Pages",
icon: Target,
color: "#ef4444",
bg: "#fff5f5",
},
{
type: "route",
@ -34,64 +58,291 @@ const navigationItems: SearchItem[] = [
description: "Train speed and accuracy",
route: "/student/practice/drills",
group: "Pages",
icon: Zap,
color: "#0891b2",
bg: "#ecfeff",
},
{
type: "route",
title: "Leaderboard",
description: "View student rankings",
description: "See how you rank against others",
route: "/student/rewards",
group: "Pages",
icon: Trophy,
color: "#f97316",
bg: "#fff7ed",
},
{
type: "route",
title: "Practice",
description: "See how you can practice",
description: "Browse all practice modes",
route: "/student/practice",
group: "Pages",
icon: BookOpen,
color: "#a855f7",
bg: "#fdf4ff",
},
{
type: "route",
title: "Lessons",
description: "Watch detailed lessons on SAT techniques",
description: "Watch expert SAT technique lessons",
route: "/student/lessons",
group: "Pages",
icon: BookOpen,
color: "#0891b2",
bg: "#ecfeff",
},
{
type: "route",
title: "Profile",
description: "View your profile",
description: "View your profile and settings",
route: "/student/profile",
group: "Pages",
icon: User,
color: "#e11d48",
bg: "#fff1f2",
},
{
type: "route",
title: "Home",
description: "Go back to home",
route: "/student/home",
group: "Pages",
icon: Home,
color: "#f97316",
bg: "#fff7ed",
},
];
const NAV_MAP = Object.fromEntries(NAV_ITEMS.map((n) => [n.route, n]));
const STATUS_META = {
IN_PROGRESS: {
label: "In Progress",
color: "#9333ea",
bg: "#f3e8ff",
icon: "🔄",
},
COMPLETED: {
label: "Completed",
color: "#16a34a",
bg: "#f0fdf4",
icon: "✅",
},
NOT_STARTED: {
label: "Not Started",
color: "#6b7280",
bg: "#f3f4f6",
icon: "📋",
},
};
// ─── Recent items (session memory) ───────────────────────────────────────────
const SESSION_KEY = "so_recent";
const MAX_RECENT = 5;
const getRecent = (): SearchItem[] => {
try {
return JSON.parse(sessionStorage.getItem(SESSION_KEY) ?? "[]");
} catch {
return [];
}
};
const addRecent = (item: SearchItem) => {
const prev = getRecent().filter((r) => r.route !== item.route);
const next = [item, ...prev].slice(0, MAX_RECENT);
sessionStorage.setItem(SESSION_KEY, JSON.stringify(next));
};
// ─── Highlight helper ─────────────────────────────────────────────────────────
const highlightText = (text: string, query: string) => {
if (!query.trim()) return text;
const escapedQuery = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const regex = new RegExp(`(${escapedQuery})`, "gi");
if (!query.trim()) return <>{text}</>;
const esc = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const regex = new RegExp(`(${esc})`, "gi");
const parts = text.split(regex);
return parts.map((part, index) => {
const isMatch = part.toLowerCase() === query.toLowerCase();
return isMatch ? (
<motion.span
key={index}
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.2, delay: index * 0.05 }}
className="bg-purple-200 text-purple-900 px-1 rounded-md"
return (
<>
{parts.map((part, i) =>
part.toLowerCase() === query.toLowerCase() ? (
<mark
key={i}
style={{
background: "#e9d5ff",
color: "#6b21a8",
borderRadius: 4,
padding: "0 2px",
}}
>
{part}
</motion.span>
</mark>
) : (
part
),
)}
</>
);
});
};
// ─── Styles ───────────────────────────────────────────────────────────────────
const STYLES = `
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@700;800;900&family=Nunito+Sans:wght@400;600;700&display=swap');
.so-overlay {
position: fixed; inset: 0; z-index: 50;
background: rgba(0,0,0,0.35);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
display: flex; flex-direction: column;
align-items: center; padding-top: 5rem;
padding-left: 1rem; padding-right: 1rem;
}
.so-box {
width: 100%; max-width: 560px;
background: #fffbf4;
border: 2.5px solid #f3f4f6;
border-radius: 28px;
box-shadow: 0 20px 60px rgba(0,0,0,0.18), 0 6px 16px rgba(0,0,0,0.08);
overflow: hidden;
display: flex; flex-direction: column;
max-height: calc(100vh - 6rem);
}
/* Input row */
.so-input-row {
display: flex; align-items: center; gap: 0.75rem;
padding: 1rem 1.25rem;
border-bottom: 2px solid #f3f4f6;
flex-shrink: 0;
}
.so-input {
flex: 1; outline: none; border: none; background: transparent;
font-family: 'Nunito', sans-serif;
font-size: 0.95rem; font-weight: 800; color: #1e1b4b;
}
.so-input::placeholder { color: #d1d5db; font-weight: 700; }
.so-close-btn {
width: 30px; height: 30px; border-radius: 50%; border: 2.5px solid #f3f4f6;
background: white; cursor: pointer; flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
transition: all 0.15s ease;
}
.so-close-btn:hover { border-color: #fecdd3; background: #fff1f2; }
/* Scrollable results */
.so-results {
overflow-y: auto; flex: 1;
padding: 0.75rem 0.75rem 1rem;
-webkit-overflow-scrolling: touch;
display: flex; flex-direction: column; gap: 1rem;
}
/* Section label */
.so-section-label {
font-size: 0.58rem; font-weight: 800; letter-spacing: 0.18em;
text-transform: uppercase; color: #9ca3af;
padding: 0 0.5rem; margin-bottom: -0.35rem;
display: flex; align-items: center; gap: 0.4rem;
}
/* Result rows */
.so-item {
display: flex; align-items: center; gap: 0.75rem;
padding: 0.7rem 0.75rem; border-radius: 16px; cursor: pointer;
transition: background 0.15s ease, transform 0.1s ease;
border: 2px solid transparent;
}
.so-item:hover {
background: white; border-color: #f3f4f6;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
transform: translateX(2px);
}
.so-item:active { transform: scale(0.98); }
.so-item-icon {
width: 36px; height: 36px; border-radius: 11px; flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
font-size: 0.85rem;
}
.so-item-body { flex: 1; min-width: 0; }
.so-item-title {
font-family: 'Nunito', sans-serif;
font-size: 0.88rem; font-weight: 900; color: #1e1b4b;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.so-item-desc {
font-family: 'Nunito Sans', sans-serif;
font-size: 0.72rem; font-weight: 600; color: #9ca3af;
margin-top: 0.05rem;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.so-item-arrow { color: #d1d5db; flex-shrink: 0; transition: color 0.15s ease; }
.so-item:hover .so-item-arrow { color: #a855f7; }
/* Sheet status chip inline */
.so-status-chip {
font-size: 0.6rem; font-weight: 800; letter-spacing: 0.08em;
text-transform: uppercase; border-radius: 100px; padding: 0.15rem 0.5rem;
flex-shrink: 0;
}
/* Quick nav chips (shown when empty query) */
.so-quick-wrap {
display: flex; flex-wrap: wrap; gap: 0.5rem; padding: 0 0.25rem;
}
.so-quick-chip {
display: flex; align-items: center; gap: 0.4rem;
background: white; border: 2.5px solid #f3f4f6; border-radius: 100px;
padding: 0.45rem 0.85rem; cursor: pointer;
font-family: 'Nunito', sans-serif; font-size: 0.75rem; font-weight: 800;
color: #6b7280;
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
transition: all 0.15s ease;
}
.so-quick-chip:hover { transform: translateY(-2px); box-shadow: 0 6px 14px rgba(0,0,0,0.07); border-color: #e9d5ff; color: #a855f7; }
/* Empty state */
.so-empty {
display: flex; flex-direction: column; align-items: center;
padding: 2rem 1rem; gap: 0.5rem;
font-family: 'Nunito Sans', sans-serif;
}
.so-empty-emoji { font-size: 2rem; }
.so-empty-text { font-size: 0.85rem; font-weight: 700; color: #9ca3af; }
.so-empty-sub { font-size: 0.75rem; font-weight: 600; color: #d1d5db; text-align: center; }
/* Keyboard hint */
.so-kbd-row {
display: flex; align-items: center; justify-content: center; gap: 1rem;
padding: 0.6rem 1rem;
border-top: 2px solid #f9fafb;
flex-shrink: 0;
}
.so-kbd-hint {
display: flex; align-items: center; gap: 0.3rem;
font-family: 'Nunito Sans', sans-serif;
font-size: 0.62rem; font-weight: 600; color: #d1d5db;
}
.so-kbd {
background: white; border: 1.5px solid #e5e7eb; border-radius: 5px;
padding: 0.1rem 0.4rem; font-size: 0.6rem; font-weight: 800;
color: #9ca3af; box-shadow: 0 1px 0 #d1d5db;
}
/* Highlight count badge */
.so-count-badge {
font-family: 'Nunito', sans-serif;
font-size: 0.65rem; font-weight: 800;
background: #f3e8ff; color: #9333ea;
border-radius: 100px; padding: 0.15rem 0.5rem; flex-shrink: 0;
}
`;
// ─── Main component ───────────────────────────────────────────────────────────
export const SearchOverlay = ({
sheets,
onClose,
@ -99,132 +350,331 @@ export const SearchOverlay = ({
setSearchQuery,
}: Props) => {
const navigate = useNavigate();
const inputRef = useRef<HTMLInputElement>(null);
const [recent, setRecent] = useState<SearchItem[]>(getRecent);
const [focused, setFocused] = useState(-1); // keyboard nav index
// Build full search item list
const searchItems = useMemo<SearchItem[]>(() => {
const sheetItems = sheets.map((sheet) => ({
type: "sheet",
type: "sheet" as const,
id: sheet.id,
title: sheet.title,
description: sheet.description,
description: sheet.description ?? "Practice sheet",
route: `/student/practice/${sheet.id}`,
group: formatGroupTitle(sheet.user_status), // 👈 reuse your grouping
group: formatGroupTitle(sheet.user_status),
status: sheet.user_status,
}));
return [...navigationItems, ...sheetItems];
return [...NAV_ITEMS, ...sheetItems];
}, [sheets]);
// Close on ESC
useEffect(() => {
const handleKey = (e: KeyboardEvent) => {
if (e.key === "Escape") onClose();
};
window.addEventListener("keydown", handleKey);
return () => window.removeEventListener("keydown", handleKey);
}, [onClose]);
// Filtered + grouped results
const groupedResults = useMemo(() => {
if (!searchQuery.trim()) return {};
const q = searchQuery.toLowerCase();
const filtered = searchItems.filter((item) => {
const title = item.title?.toLowerCase() || "";
const description = item.description?.toLowerCase() || "";
return title.includes(q) || description.includes(q);
});
const filtered = searchItems.filter(
(item) =>
item.title?.toLowerCase().includes(q) ||
item.description?.toLowerCase().includes(q),
);
return filtered.reduce<Record<string, SearchItem[]>>((acc, item) => {
if (!acc[item.group]) {
acc[item.group] = [];
}
acc[item.group].push(item);
(acc[item.group] ??= []).push(item);
return acc;
}, {});
}, [searchQuery, searchItems]);
const flatResults = useMemo(
() => Object.values(groupedResults).flat(),
[groupedResults],
);
// ESC to close, arrow keys + enter for keyboard nav
useEffect(() => {
const handle = (e: KeyboardEvent) => {
if (e.key === "Escape") {
onClose();
return;
}
if (e.key === "ArrowDown") {
e.preventDefault();
setFocused((f) => Math.min(f + 1, flatResults.length - 1));
}
if (e.key === "ArrowUp") {
e.preventDefault();
setFocused((f) => Math.max(f - 1, 0));
}
if (e.key === "Enter" && focused >= 0 && flatResults[focused]) {
handleSelect(flatResults[focused]);
}
};
window.addEventListener("keydown", handle);
return () => window.removeEventListener("keydown", handle);
}, [onClose, focused, flatResults]);
// Reset focused when query changes
useEffect(() => {
setFocused(-1);
}, [searchQuery]);
const handleSelect = (item: SearchItem) => {
addRecent(item);
setRecent(getRecent());
onClose();
navigate(item.route!);
};
const totalCount = flatResults.length;
return (
<AnimatePresence>
<motion.div
className="fixed inset-0 z-50 bg-black/40 backdrop-blur-sm flex flex-col items-center pt-24 px-4"
className="so-overlay"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
>
{/* Search Box */}
<style>{STYLES}</style>
<motion.div
initial={{ y: -40, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: -40, opacity: 0 }}
transition={{ type: "spring", stiffness: 300 }}
className="so-box"
initial={{ y: -24, opacity: 0, scale: 0.97 }}
animate={{ y: 0, opacity: 1, scale: 1 }}
exit={{ y: -24, opacity: 0, scale: 0.97 }}
transition={{ type: "spring", stiffness: 380, damping: 28 }}
onClick={(e) => e.stopPropagation()}
className="w-full max-w-2xl bg-white rounded-3xl shadow-2xl p-6"
>
<div className="flex items-center gap-3">
<Search size={20} />
{/* Input row */}
<div className="so-input-row">
<Search size={18} color="#9ca3af" />
<input
ref={inputRef}
autoFocus
className="so-input"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Search..."
className="flex-1 outline-none font-satoshi text-lg"
placeholder="Search sheets, pages, topics..."
/>
<button onClick={onClose}>
<X size={20} />
{searchQuery && totalCount > 0 && (
<span className="so-count-badge">
{totalCount} result{totalCount !== 1 ? "s" : ""}
</span>
)}
<button className="so-close-btn" onClick={onClose}>
<X size={13} color="#9ca3af" />
</button>
</div>
{/* Results */}
<div className="mt-6 max-h-96 overflow-y-auto space-y-6">
{/* {!searchQuery && (
<p className="font-satoshi text-gray-500">
Start typing to search...
<div className="so-results">
{/* ── Empty query: recent + quick nav ── */}
{!searchQuery && (
<>
{recent.length > 0 && (
<div>
<p className="so-section-label">
<Clock size={10} /> Recent
</p>
)} */}
{searchQuery.length === 0 ? (
<p className="text-gray-400 font-satoshi">
Start typing to search...
</p>
) : Object.keys(groupedResults).length === 0 ? (
<p className="text-gray-400 font-satoshi">No results found.</p>
) : (
Object.entries(groupedResults).map(([group, items]) => (
<div key={group}>
<p className="text-xs uppercase tracking-wider text-gray-400 font-satoshi mb-3">
{group}
</p>
<div className="space-y-2">
{items.map((item, index) => (
{recent.map((item, i) => {
const navMeta = NAV_MAP[item.route!];
const Icon = navMeta?.icon ?? BookOpen;
const color = navMeta?.color ?? "#a855f7";
const bg = navMeta?.bg ?? "#fdf4ff";
return (
<div
key={index}
onClick={() => {
onClose();
navigate(item.route!);
}}
className="p-4 rounded-2xl hover:bg-gray-100 cursor-pointer transition"
key={i}
className="so-item"
onClick={() => handleSelect(item)}
>
<p className="font-satoshi-medium">
{highlightText(item.title, searchQuery)}
</p>
<div
className="so-item-icon"
style={{ background: bg }}
>
<Icon size={16} color={color} />
</div>
<div className="so-item-body">
<p className="so-item-title">{item.title}</p>
{item.description && (
<p className="text-sm text-gray-500">
{highlightText(item.description, searchQuery)}
</p>
<p className="so-item-desc">{item.description}</p>
)}
</div>
<ArrowRight size={15} className="so-item-arrow" />
</div>
);
})}
</div>
)}
<p className="text-xs text-purple-500 mt-1">
{item.type === "route" ? "" : "Practice Sheet"}
</p>
</div>
<div>
<p className="so-section-label"> Quick nav</p>
<div
className="so-quick-wrap"
style={{ marginTop: "0.5rem" }}
>
{NAV_ITEMS.map((item, i) => (
<button
key={i}
className="so-quick-chip"
onClick={() => handleSelect(item)}
>
<item.icon size={13} color={item.color} />
{item.title}
</button>
))}
</div>
</div>
))
{sheets.length > 0 && (
<div>
<p className="so-section-label">
<Flame size={10} /> In progress
</p>
{sheets
.filter((s) => s.user_status === "IN_PROGRESS")
.slice(0, 3)
.map((sheet) => {
const item: SearchItem = {
type: "sheet",
title: sheet.title,
description: sheet.description,
route: `/student/practice/${sheet.id}`,
group: "In Progress",
status: sheet.user_status,
};
return (
<div
key={sheet.id}
className="so-item"
onClick={() => handleSelect(item)}
>
<div
className="so-item-icon"
style={{ background: "#f3e8ff" }}
>
<BookOpen size={16} color="#a855f7" />
</div>
<div className="so-item-body">
<p className="so-item-title">{sheet.title}</p>
{sheet.description && (
<p className="so-item-desc">
{sheet.description}
</p>
)}
</div>
<span
className="so-status-chip"
style={{
background: "#f3e8ff",
color: "#9333ea",
}}
>
In Progress
</span>
</div>
);
})}
</div>
)}
</>
)}
{/* ── No results ── */}
{searchQuery && totalCount === 0 && (
<div className="so-empty">
<span className="so-empty-emoji">🔍</span>
<p className="so-empty-text">No results for "{searchQuery}"</p>
<p className="so-empty-sub">
Try searching for a topic, sheet title, or page name
</p>
</div>
)}
{/* ── Results grouped ── */}
{searchQuery &&
totalCount > 0 &&
Object.entries(groupedResults).map(([group, items]) => (
<div key={group}>
<p className="so-section-label">{group}</p>
{items.map((item, index) => {
const globalIdx = flatResults.indexOf(item);
const isFocused = globalIdx === focused;
const navMeta = NAV_MAP[item.route!];
const Icon = navMeta?.icon ?? BookOpen;
const iconColor = navMeta?.color ?? "#a855f7";
const iconBg = navMeta?.bg ?? "#fdf4ff";
const statusMeta = item.status
? STATUS_META[item.status as keyof typeof STATUS_META]
: null;
return (
<motion.div
key={index}
className="so-item"
style={{
background: isFocused ? "white" : undefined,
borderColor: isFocused ? "#e9d5ff" : undefined,
boxShadow: isFocused
? "0 4px 12px rgba(0,0,0,0.06)"
: undefined,
}}
initial={{ opacity: 0, y: 6 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.03 }}
onClick={() => handleSelect(item)}
>
<div
className="so-item-icon"
style={{ background: iconBg }}
>
{item.type === "sheet" ? (
<span style={{ fontSize: "1rem" }}>
{statusMeta?.icon ?? "📋"}
</span>
) : (
<Icon size={16} color={iconColor} />
)}
</div>
<div className="so-item-body">
<p className="so-item-title">
{highlightText(item.title, searchQuery)}
</p>
{item.description && (
<p className="so-item-desc">
{highlightText(item.description, searchQuery)}
</p>
)}
</div>
{statusMeta && (
<span
className="so-status-chip"
style={{
background: statusMeta.bg,
color: statusMeta.color,
}}
>
{statusMeta.label}
</span>
)}
<ArrowRight size={15} className="so-item-arrow" />
</motion.div>
);
})}
</div>
))}
</div>
{/* Keyboard hints */}
<div className="so-kbd-row">
<div className="so-kbd-hint">
<kbd className="so-kbd"></kbd> Navigate
</div>
<div className="so-kbd-hint">
<kbd className="so-kbd"></kbd> Open
</div>
<div className="so-kbd-hint">
<kbd className="so-kbd">Esc</kbd> Close
</div>
</div>
</motion.div>
</motion.div>
</AnimatePresence>

View File

@ -0,0 +1,87 @@
import React, { useState } from 'react';
const BoxPlotAnatomyWidget: React.FC = () => {
const [q1, setQ1] = useState(20);
const [q3, setQ3] = useState(60);
const [med, setMed] = useState(40);
const min = 10;
const max = 90;
// Enforce constraints
const handleMedChange = (val: number) => {
setMed(Math.max(q1, Math.min(q3, val)));
};
const handleQ1Change = (val: number) => {
const newQ1 = Math.min(val, med);
setQ1(Math.max(min, newQ1));
};
const handleQ3Change = (val: number) => {
const newQ3 = Math.max(val, med);
setQ3(Math.min(max, newQ3));
};
const scale = (val: number) => ((val) / 100) * 100; // 0-100 domain mapped to %
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200 select-none">
<div className="relative h-40 mt-8 mb-4">
{/* Axis Line */}
<div className="absolute top-1/2 left-[10%] right-[10%] h-0.5 bg-slate-300 -translate-y-1/2"></div>
{/* Range Line (Whiskers) */}
<div className="absolute top-1/2 bg-slate-800 h-0.5 -translate-y-1/2 transition-all"
style={{ left: `${scale(min)}%`, right: `${100 - scale(max)}%` }}></div>
{/* Endpoints (Min/Max) */}
<div className="absolute top-1/2 h-4 w-0.5 bg-slate-800 -translate-y-1/2" style={{ left: `${scale(min)}%` }}>
<span className="absolute -top-6 left-1/2 -translate-x-1/2 text-xs font-bold text-slate-500">Min</span>
</div>
<div className="absolute top-1/2 h-4 w-0.5 bg-slate-800 -translate-y-1/2" style={{ left: `${scale(max)}%` }}>
<span className="absolute -top-6 left-1/2 -translate-x-1/2 text-xs font-bold text-slate-500">Max</span>
</div>
{/* The Box */}
<div className="absolute top-1/2 -translate-y-1/2 h-16 bg-amber-100 border-2 border-amber-500 rounded-sm transition-all"
style={{ left: `${scale(q1)}%`, width: `${scale(q3) - scale(q1)}%` }}>
{/* Median Line */}
<div className="absolute top-0 bottom-0 w-1 bg-amber-600 left-[50%] -translate-x-1/2 transition-all"
style={{ left: `${((med - q1) / (q3 - q1)) * 100}%` }}>
</div>
</div>
{/* Labels below for Q1, Med, Q3 */}
<div className="absolute top-[70%] text-xs font-bold text-amber-700 -translate-x-1/2 transition-all" style={{ left: `${scale(q1)}%` }}>Q1</div>
<div className="absolute top-[70%] text-xs font-bold text-amber-900 -translate-x-1/2 transition-all" style={{ left: `${scale(med)}%` }}>Median</div>
<div className="absolute top-[70%] text-xs font-bold text-amber-700 -translate-x-1/2 transition-all" style={{ left: `${scale(q3)}%` }}>Q3</div>
</div>
<div className="grid grid-cols-3 gap-6 mt-8">
<div>
<label className="text-xs font-bold text-slate-400 uppercase">Q1 (25th %)</label>
<input type="range" min={min} max={max} value={q1} onChange={e => handleQ1Change(parseInt(e.target.value))}
className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-amber-500"/>
</div>
<div>
<label className="text-xs font-bold text-slate-400 uppercase">Median (50th %)</label>
<input type="range" min={min} max={max} value={med} onChange={e => handleMedChange(parseInt(e.target.value))}
className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-amber-700"/>
</div>
<div>
<label className="text-xs font-bold text-slate-400 uppercase">Q3 (75th %)</label>
<input type="range" min={min} max={max} value={q3} onChange={e => handleQ3Change(parseInt(e.target.value))}
className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-amber-500"/>
</div>
</div>
<div className="mt-6 p-4 bg-amber-50 border border-amber-100 rounded-lg text-center">
<div className="text-sm font-mono text-amber-900">
IQR (Box Width) = <span className="font-bold">{q3 - q1}</span>
</div>
<p className="text-xs text-amber-700/70 mt-1">The middle 50% of data lies inside the box.</p>
</div>
</div>
);
};
export default BoxPlotAnatomyWidget;

View File

@ -0,0 +1,111 @@
import React, { useState } from 'react';
const BoxPlotComparisonWidget: React.FC = () => {
// Box Plot A is fixed
const statsA = { min: 10, q1: 18, med: 24, q3: 30, max: 42 };
// Box Plot B is adjustable
const [shift, setShift] = useState(0); // Shift median
const [spread, setSpread] = useState(1); // Scale spread
const statsB = {
min: 10 + shift - (5 * (spread - 1)), // Just approximating visual expansion
q1: 16 + shift - (2 * (spread - 1)),
med: 26 + shift,
q3: 34 + shift + (2 * (spread - 1)),
max: 38 + shift + (4 * (spread - 1))
};
const scaleX = (val: number) => (val / 60) * 100; // 0 to 60 range mapping to %
const BoxPlot = ({ stats, color, label }: { stats: any, color: string, label: string }) => {
const leftW = scaleX(stats.min);
const rightW = scaleX(stats.max);
const boxL = scaleX(stats.q1);
const boxR = scaleX(stats.q3);
const med = scaleX(stats.med);
return (
<div className="relative h-16 w-full mb-8 group">
<div className="absolute left-0 top-0 text-xs font-bold text-slate-400">{label}</div>
{/* Main Line (Whisker to Whisker) */}
<div className="absolute top-1/2 left-0 h-0.5 bg-slate-300 -translate-y-1/2"
style={{ left: `${leftW}%`, width: `${rightW - leftW}%` }} />
{/* Whiskers */}
<div className="absolute top-1/2 h-3 w-0.5 bg-slate-400 -translate-y-1/2" style={{ left: `${leftW}%` }} />
<div className="absolute top-1/2 h-3 w-0.5 bg-slate-400 -translate-y-1/2" style={{ left: `${rightW}%` }} />
{/* Box */}
<div className={`absolute top-1/2 -translate-y-1/2 h-8 border-2 ${color} bg-white opacity-90`}
style={{ left: `${boxL}%`, width: `${boxR - boxL}%`, borderColor: 'currentColor' }}>
</div>
{/* Median Line */}
<div className="absolute top-1/2 h-8 w-1 bg-slate-800 -translate-y-1/2" style={{ left: `${med}%` }} />
{/* Labels on Hover */}
<div className="opacity-0 group-hover:opacity-100 transition-opacity absolute top-10 left-0 w-full text-center text-xs font-mono text-slate-500 pointer-events-none">
Min:{stats.min.toFixed(0)} Q1:{stats.q1.toFixed(0)} Med:{stats.med.toFixed(0)} Q3:{stats.q3.toFixed(0)} Max:{stats.max.toFixed(0)}
</div>
</div>
);
};
const iqrA = statsA.q3 - statsA.q1;
const iqrB = statsB.q3 - statsB.q1;
const rangeA = statsA.max - statsA.min;
const rangeB = statsB.max - statsB.min;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="mb-6 relative h-48 border-b border-slate-200">
<BoxPlot stats={statsA} color="text-indigo-500" label="Dataset A (Fixed)" />
<BoxPlot stats={statsB} color="text-rose-500" label="Dataset B (Adjustable)" />
{/* Axis */}
<div className="absolute bottom-0 w-full flex justify-between text-xs text-slate-400 font-mono px-2">
<span>0</span><span>10</span><span>20</span><span>30</span><span>40</span><span>50</span><span>60</span>
</div>
</div>
<div className="flex flex-col md:flex-row gap-8">
<div className="w-full md:w-1/3 space-y-6">
<div>
<label className="text-xs font-bold text-slate-500 uppercase">Shift Center (Median B)</label>
<input type="range" min="-15" max="15" value={shift} onChange={e => setShift(parseInt(e.target.value))} className="w-full h-2 bg-rose-100 rounded-lg appearance-none cursor-pointer accent-rose-600"/>
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase">Adjust Spread (IQR B)</label>
<input type="range" min="0.5" max="2" step="0.1" value={spread} onChange={e => setSpread(parseFloat(e.target.value))} className="w-full h-2 bg-rose-100 rounded-lg appearance-none cursor-pointer accent-rose-600"/>
</div>
</div>
<div className="flex-1 grid grid-cols-2 gap-4">
<div className="bg-slate-50 p-3 rounded border border-slate-200">
<div className="text-xs font-bold text-slate-400 uppercase">Median Comparison</div>
<div className="flex justify-between items-center mt-1">
<span className="text-indigo-600 font-bold">{statsA.med}</span>
<span className="text-slate-400">{statsA.med > statsB.med ? '>' : statsA.med < statsB.med ? '<' : '='}</span>
<span className="text-rose-600 font-bold">{statsB.med}</span>
</div>
</div>
<div className="bg-slate-50 p-3 rounded border border-slate-200">
<div className="text-xs font-bold text-slate-400 uppercase">IQR Comparison</div>
<div className="flex justify-between items-center mt-1">
<span className="text-indigo-600 font-bold">{iqrA.toFixed(0)}</span>
<span className="text-slate-400">{iqrA > iqrB ? '>' : iqrA < iqrB ? '<' : '='}</span>
<span className="text-rose-600 font-bold">{iqrB.toFixed(0)}</span>
</div>
</div>
<div className="col-span-2 text-xs text-slate-500 text-center">
The box length represents the IQR (Middle 50%). The whiskers represent the full Range.
</div>
</div>
</div>
</div>
);
};
export default BoxPlotComparisonWidget;

View File

@ -0,0 +1,121 @@
import React, { useState, useRef, useEffect } from 'react';
const CircleTheoremsWidget: React.FC = () => {
// C is the point on the major arc
const [angleC, setAngleC] = useState(230); // Position in degrees on the circle
const svgRef = useRef<SVGSVGElement>(null);
const isDragging = useRef(false);
const R = 120;
const center = { x: 200, y: 180 };
// Fixed points A and B at the bottom
const angleA = 330; // 30 deg below x axis
const angleB = 210; // 150 deg below x axis? No, let's place them symmetrically
// Let's place A and B to define a nice arc
// A at -30 deg (330), B at 210 is too far.
// Let's put A at 320 (-40) and B at 220 (-140).
// Wait, standard unit circle angles.
// A at 340 (-20), B at 200. Arc is 140 deg at bottom.
// Major arc is top. C moves on top.
const posA = { x: center.x + R * Math.cos(340 * Math.PI/180), y: center.y - R * Math.sin(340 * Math.PI/180) }; // SVG y inverted logic?
// Let's just use standard math cos/sin and add to center.y
// SVG y is positive down.
const getPos = (deg: number) => ({
x: center.x + R * Math.cos(deg * Math.PI / 180),
y: center.y + R * Math.sin(deg * Math.PI / 180)
});
const A = getPos(30); // Bottom Right
const B = getPos(150); // Bottom Left
// Central angle is 120 degrees (150 - 30).
const centralAngleValue = 120;
const handleMouseMove = (e: React.MouseEvent) => {
if (!isDragging.current || !svgRef.current) return;
const rect = svgRef.current.getBoundingClientRect();
const dx = e.clientX - rect.left - center.x;
const dy = e.clientY - rect.top - center.y;
let deg = Math.atan2(dy, dx) * 180 / Math.PI;
if (deg < 0) deg += 360;
// Constrain C to the major arc (approx 160 to 350 is the "bad" zone? No, A=30, B=150.
// Bad zone is between 30 and 150 (the minor arc).
// Let's allow C anywhere except the minor arc to avoid crossing lines weirdly.
if (deg > 40 && deg < 140) return; // Simple constraint
setAngleC(deg);
};
const C = getPos(angleC);
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200 flex flex-col items-center">
<h3 className="font-bold text-slate-700 mb-2">Central vs. Inscribed Angle</h3>
<div className="text-sm text-slate-500 mb-4 text-center max-w-md">
Drag point <strong className="text-emerald-600">C</strong> along the top arc. Notice that the inscribed angle stays constant!
</div>
<svg
ref={svgRef}
width="400"
height="350"
onMouseMove={handleMouseMove}
onMouseUp={() => isDragging.current = false}
onMouseLeave={() => isDragging.current = false}
className="select-none"
>
{/* Circle */}
<circle cx={center.x} cy={center.y} r={R} stroke="#cbd5e1" strokeWidth="2" fill="transparent" />
{/* Central Angle Lines */}
<path d={`M ${A.x} ${A.y} L ${center.x} ${center.y} L ${B.x} ${B.y}`} stroke="#e2e8f0" strokeWidth="2" fill="transparent" strokeDasharray="5,5"/>
{/* Central Angle Wedge */}
{/* 30 to 150 */}
<path d={`M ${center.x} ${center.y} L ${A.x} ${A.y} A ${R} ${R} 0 0 1 ${B.x} ${B.y} Z`} fill="rgba(99, 102, 241, 0.1)" stroke="none" />
<text x={center.x} y={center.y + 40} textAnchor="middle" className="text-sm font-bold fill-indigo-600">{centralAngleValue}°</text>
<text x={center.x} y={center.y + 60} textAnchor="middle" className="text-xs fill-indigo-400 uppercase">Central</text>
{/* Inscribed Angle Lines */}
<path d={`M ${A.x} ${A.y} L ${C.x} ${C.y} L ${B.x} ${B.y}`} stroke="#059669" strokeWidth="3" fill="transparent" strokeLinejoin="round" />
{/* Points */}
<circle cx={center.x} cy={center.y} r="4" fill="#64748b" /> {/* Center */}
<text x={center.x + 10} y={center.y} className="text-xs fill-slate-400">O</text>
<circle cx={A.x} cy={A.y} r="5" fill="#475569" />
<text x={A.x + 10} y={A.y} className="text-xs font-bold fill-slate-600">A</text>
<circle cx={B.x} cy={B.y} r="5" fill="#475569" />
<text x={B.x - 20} y={B.y} className="text-xs font-bold fill-slate-600">B</text>
{/* Draggable C */}
<g onMouseDown={() => isDragging.current = true} className="cursor-grab active:cursor-grabbing">
<circle cx={C.x} cy={C.y} r="15" fill="transparent" /> {/* Hit area */}
<circle cx={C.x} cy={C.y} r="8" fill="#059669" stroke="white" strokeWidth="2" className="shadow-lg" />
<text x={C.x} y={C.y - 15} textAnchor="middle" className="text-sm font-bold fill-emerald-700">C</text>
</g>
{/* Inscribed Angle Label */}
{/* Simple approximation for label placement: slightly "in" from C towards center */}
<text x={C.x + (center.x - C.x)*0.2} y={C.y + (center.y - C.y)*0.2 + 5} textAnchor="middle" className="text-lg font-bold fill-emerald-600">
{centralAngleValue / 2}°
</text>
</svg>
<div className="bg-slate-50 p-4 rounded-lg border border-slate-200 mt-4 w-full text-center">
<p className="font-mono text-lg text-slate-800">
Inscribed Angle = <span className="text-emerald-600">½</span> × Central Angle
</p>
<p className="font-mono text-md text-slate-600 mt-1">
{centralAngleValue / 2}° = ½ × {centralAngleValue}°
</p>
</div>
</div>
);
};
export default CircleTheoremsWidget;

View File

@ -0,0 +1,163 @@
import React, { useState } from 'react';
import { MousePointerClick } from 'lucide-react';
export type SegmentType = 'ic' | 'dc' | 'modifier' | 'conjunction' | 'punct' | 'subject' | 'verb';
export interface Segment {
text: string;
type: SegmentType;
label?: string;
}
export interface ClauseExample {
title: string;
segments: Segment[];
}
interface ClauseBreakdownWidgetProps {
examples: ClauseExample[];
accentColor?: string;
}
const TYPE_STYLES: Record<SegmentType, { bg: string; text: string; border: string; ring: string }> = {
ic: { bg: 'bg-blue-100', text: 'text-blue-800', border: 'border-blue-300', ring: '#93c5fd' },
dc: { bg: 'bg-green-100', text: 'text-green-800', border: 'border-green-300', ring: '#86efac' },
modifier: { bg: 'bg-orange-100', text: 'text-orange-800', border: 'border-orange-300', ring: '#fdba74' },
conjunction: { bg: 'bg-purple-100', text: 'text-purple-800', border: 'border-purple-300', ring: '#c4b5fd' },
subject: { bg: 'bg-sky-100', text: 'text-sky-800', border: 'border-sky-300', ring: '#7dd3fc' },
verb: { bg: 'bg-rose-100', text: 'text-rose-800', border: 'border-rose-300', ring: '#fda4af' },
punct: { bg: 'bg-gray-100', text: 'text-gray-600', border: 'border-gray-300', ring: '#d1d5db' },
};
const TYPE_LABELS: Record<SegmentType, string> = {
ic: 'Independent Clause',
dc: 'Dependent Clause',
modifier: 'Modifier',
conjunction: 'Conjunction',
subject: 'Subject',
verb: 'Verb / Predicate',
punct: 'Punctuation',
};
// Pre-resolved tab accent classes (avoids Tailwind purge issues with dynamic strings)
const TAB_ACTIVE: Record<string, string> = {
purple: 'border-b-2 border-purple-600 text-purple-700 bg-white',
teal: 'border-b-2 border-teal-600 text-teal-700 bg-white',
fuchsia: 'border-b-2 border-fuchsia-600 text-fuchsia-700 bg-white',
amber: 'border-b-2 border-amber-600 text-amber-700 bg-white',
};
export default function ClauseBreakdownWidget({ examples, accentColor = 'purple' }: ClauseBreakdownWidgetProps) {
const [activeTab, setActiveTab] = useState(0);
const [selected, setSelected] = useState<number | null>(null);
const example = examples[activeTab];
const switchTab = (i: number) => { setActiveTab(i); setSelected(null); };
const selectedSeg = selected !== null ? example.segments[selected] : null;
const tabActive = TAB_ACTIVE[accentColor] ?? TAB_ACTIVE.purple;
// Unique labeled segment types for the legend
const legendTypes = Array.from(
new Set(example.segments.filter(s => s.label).map(s => s.type))
);
return (
<div className="rounded-2xl border border-gray-200 bg-white overflow-hidden shadow-sm">
{/* Tab strip */}
{examples.length > 1 && (
<div className="flex border-b border-gray-200 bg-gray-50 overflow-x-auto">
{examples.map((ex, i) => (
<button
key={i}
onClick={() => switchTab(i)}
className={`px-4 py-2.5 text-sm font-medium whitespace-nowrap transition-colors ${
i === activeTab ? tabActive : 'text-gray-500 hover:text-gray-700'
}`}
>
{ex.title}
</button>
))}
</div>
)}
{examples.length === 1 && (
<div className="px-5 pt-4 pb-1">
<p className="text-xs font-semibold uppercase tracking-wider text-gray-400">{example.title}</p>
</div>
)}
{/* Instruction */}
<div className="px-5 pt-3 pb-1 flex items-center gap-1.5">
<MousePointerClick className="w-3.5 h-3.5 text-gray-400 shrink-0" />
<p className="text-xs text-gray-400 italic">Click any colored part to see its grammatical role</p>
</div>
{/* Sentence display */}
<div className="px-5 pt-2 pb-3">
<div className="text-base leading-10 bg-gray-50 rounded-xl border border-gray-200 px-5 py-4 select-none">
{example.segments.map((seg, i) => {
if (!seg.label) {
// Punctuation / unlabeled — plain unstyled text, not clickable
return <span key={i} className="text-gray-700">{seg.text}</span>;
}
const style = TYPE_STYLES[seg.type];
const isSelected = selected === i;
return (
<span
key={i}
onClick={() => setSelected(isSelected ? null : i)}
className={`inline cursor-pointer rounded px-1 py-0.5 mx-0.5 transition-all ${style.bg} ${style.text} ${
isSelected
? `border-2 ${style.border} font-semibold`
: `border ${style.border} hover:opacity-80`
}`}
style={isSelected ? { outline: `2.5px solid ${style.ring}`, outlineOffset: '1px' } : {}}
>
{seg.text}
</span>
);
})}
</div>
{/* Selection indicator */}
{selectedSeg ? (
<div
className={`mt-3 rounded-xl border-2 px-4 py-3 flex items-start gap-3 ${TYPE_STYLES[selectedSeg.type].bg} ${TYPE_STYLES[selectedSeg.type].border}`}
>
<div
className="w-2.5 h-2.5 rounded-full mt-1.5 shrink-0"
style={{ backgroundColor: TYPE_STYLES[selectedSeg.type].ring }}
/>
<div className="flex-1 min-w-0">
<p className={`text-xs font-bold uppercase tracking-wider mb-0.5 ${TYPE_STYLES[selectedSeg.type].text}`}>
{selectedSeg.label ?? TYPE_LABELS[selectedSeg.type]}
</p>
<p className={`text-sm font-semibold leading-snug ${TYPE_STYLES[selectedSeg.type].text}`}>
"{selectedSeg.text.trim()}"
</p>
</div>
</div>
) : (
<p className="mt-2 text-xs text-gray-400 italic px-1">No element selected click a colored span above.</p>
)}
</div>
{/* Legend */}
<div className="px-5 py-3 border-t border-gray-100 bg-gray-50 flex flex-wrap gap-2">
{legendTypes.map(type => {
const style = TYPE_STYLES[type];
return (
<span
key={type}
className={`inline-flex items-center gap-1.5 text-xs font-medium px-2.5 py-1 rounded-full border ${style.bg} ${style.text} ${style.border}`}
>
<span className="w-2 h-2 rounded-full" style={{ backgroundColor: TYPE_STYLES[type].ring }} />
{TYPE_LABELS[type]}
</span>
);
})}
</div>
</div>
);
}

View File

@ -0,0 +1,166 @@
import React, { useState } from 'react';
// Example: x^2 + y^2 - 6x + 8y - 11 = 0
// Center (3, -4), Radius 6
// Steps:
// 1. Group: (x^2 - 6x) + (y^2 + 8y) = 11
// 2. Add magic numbers: (x^2 - 6x + 9) + (y^2 + 8y + 16) = 11 + 9 + 16
// 3. Factor: (x - 3)^2 + (y + 4)^2 = 36
const CompletingSquareWidget: React.FC = () => {
const [step, setStep] = useState(0);
const [inputs, setInputs] = useState({
magicX: '',
magicY: '',
factorX: '',
factorY: '',
totalR: ''
});
// Removed explicit generic Record<string, boolean> to prevent parsing error
const [errors, setErrors] = useState<any>({});
const correct = {
magicX: '9', // (-6/2)^2
magicY: '16', // (8/2)^2
factorX: '3', // h
factorY: '4', // -k (actually displayed as + 4)
totalR: '36' // 11 + 9 + 16
};
const handleChange = (field: string, value: string) => {
setInputs(prev => ({ ...prev, [field]: value }));
if (errors[field]) {
setErrors((prev: any) => ({ ...prev, [field]: false }));
}
};
const validateStep1 = () => {
const isXCorrect = inputs.magicX === correct.magicX;
const isYCorrect = inputs.magicY === correct.magicY;
setErrors({
magicX: !isXCorrect,
magicY: !isYCorrect
});
if (isXCorrect && isYCorrect) setStep(1);
};
const validateStep2 = () => {
const isFXCorrect = inputs.factorX === correct.factorX;
const isFYCorrect = inputs.factorY === correct.factorY;
const isRCorrect = inputs.totalR === correct.totalR;
setErrors({
factorX: !isFXCorrect,
factorY: !isFYCorrect,
totalR: !isRCorrect
});
if (isFXCorrect && isFYCorrect && isRCorrect) setStep(2);
};
return (
<div className="bg-white p-6 rounded-xl shadow-sm border border-slate-200 w-full max-w-2xl mx-auto">
<h3 className="text-lg font-bold text-slate-800 mb-4 flex items-center">
<span className="bg-indigo-100 text-indigo-700 text-xs px-2 py-1 rounded uppercase tracking-wide mr-2">Interactive</span>
Convert to Standard Form
</h3>
<div className="mb-6 p-4 bg-slate-50 rounded-lg text-center font-mono text-lg text-slate-700">
x² + y² - 6x + 8y - 11 = 0
</div>
<div className="space-y-6">
{/* Step 0: Group and Move */}
<div className={`transition-opacity duration-500 ${step >= 0 ? 'opacity-100' : 'opacity-50'}`}>
<p className="text-sm font-semibold text-slate-500 mb-2">Step 1: Group terms & move constant</p>
<div className="font-mono text-lg flex flex-wrap items-center gap-2">
<span>(x² - 6x + <input
type="text"
placeholder="?"
value={inputs.magicX}
onChange={(e) => handleChange('magicX', e.target.value)}
disabled={step > 0}
className={`w-12 text-center border-b-2 bg-transparent outline-none ${errors.magicX ? 'border-red-500 text-red-600' : 'border-slate-300'}`}
/>)</span>
<span>+</span>
<span>(y² + 8y + <input
type="text"
placeholder="?"
value={inputs.magicY}
onChange={(e) => handleChange('magicY', e.target.value)}
disabled={step > 0}
className={`w-12 text-center border-b-2 bg-transparent outline-none ${errors.magicY ? 'border-red-500 text-red-600' : 'border-slate-300'}`}
/>)</span>
<span>=</span>
<span>11 + <span className="text-indigo-600">{inputs.magicX || '?'}</span> + <span className="text-indigo-600">{inputs.magicY || '?'}</span></span>
</div>
{step === 0 && (
<div className="mt-2 text-xs text-slate-500">
Hint: Take half the coefficient of the linear term (-6 and 8), then square it.
</div>
)}
{step === 0 && (
<button
onClick={validateStep1}
className="mt-4 px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 text-sm font-medium transition-colors"
>
Check Magic Numbers
</button>
)}
</div>
{/* Step 2: Factor */}
{step >= 1 && (
<div className="animate-fade-in-up">
<p className="text-sm font-semibold text-slate-500 mb-2">Step 2: Factor & Sum</p>
<div className="font-mono text-lg flex flex-wrap items-center gap-2">
<span>(x - <input
type="text"
value={inputs.factorX}
onChange={(e) => handleChange('factorX', e.target.value)}
disabled={step > 1}
className={`w-10 text-center border-b-2 bg-transparent outline-none ${errors.factorX ? 'border-red-500' : 'border-slate-300'}`}
/>)²</span>
<span>+</span>
<span>(y + <input
type="text"
value={inputs.factorY}
onChange={(e) => handleChange('factorY', e.target.value)}
disabled={step > 1}
className={`w-10 text-center border-b-2 bg-transparent outline-none ${errors.factorY ? 'border-red-500' : 'border-slate-300'}`}
/>)²</span>
<span>=</span>
<input
type="text"
value={inputs.totalR}
onChange={(e) => handleChange('totalR', e.target.value)}
disabled={step > 1}
className={`w-16 text-center border-b-2 bg-transparent outline-none ${errors.totalR ? 'border-red-500' : 'border-slate-300'}`}
/>
</div>
{step === 1 && (
<button
onClick={validateStep2}
className="mt-4 px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 text-sm font-medium transition-colors"
>
Check Final Equation
</button>
)}
</div>
)}
{/* Step 3: Success */}
{step === 2 && (
<div className="animate-fade-in-up p-4 bg-green-50 border border-green-200 rounded-lg text-green-800">
<p className="font-bold mb-1">🎉 Awesome work!</p>
<p className="text-sm">You've successfully converted the equation. The center is (3, -4) and radius is 6 (36).</p>
</div>
)}
</div>
</div>
);
};
export default CompletingSquareWidget;

View File

@ -0,0 +1,227 @@
import React, { useState } from "react";
const CompositeAreaWidget: React.FC = () => {
const [mode, setMode] = useState<"add" | "subtract">("add");
const [width, setWidth] = useState(10);
const [height, setHeight] = useState(6);
// Scale for display
const scale = 20;
const displayW = width * scale;
const displayH = height * scale;
const radius = width / 2; // Semicircle on top (width is diameter)
const displayR = radius * scale;
// Areas
const rectArea = width * height;
const semiArea = 0.5 * Math.PI * radius * radius;
const totalArea = mode === "add" ? rectArea + semiArea : rectArea - semiArea;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200 flex flex-col items-center">
<div className="flex gap-4 mb-8">
<button
onClick={() => setMode("add")}
className={`px-4 py-2 rounded-full font-bold text-sm transition-all ${
mode === "add"
? "bg-orange-600 text-white shadow-md transform scale-105"
: "bg-slate-100 text-slate-500 hover:bg-slate-200"
}`}
>
Add Semicircle (Composite)
</button>
<button
onClick={() => setMode("subtract")}
className={`px-4 py-2 rounded-full font-bold text-sm transition-all ${
mode === "subtract"
? "bg-rose-600 text-white shadow-md transform scale-105"
: "bg-slate-100 text-slate-500 hover:bg-slate-200"
}`}
>
Subtract Semicircle (Hole)
</button>
</div>
<div
className="relative mb-8 flex items-end justify-center"
style={{ height: "300px", width: "100%" }}
>
<svg
width="400"
height="300"
className="overflow-visible transition-all duration-500"
>
<defs>
<pattern
id="grid"
width="20"
height="20"
patternUnits="userSpaceOnUse"
>
<path
d="M 20 0 L 0 0 0 20"
fill="none"
stroke="#f1f5f9"
strokeWidth="1"
/>
</pattern>
</defs>
<g transform={`translate(${200 - displayW / 2}, ${250})`}>
{/* Rectangle */}
<rect
x="0"
y={-displayH}
width={displayW}
height={displayH}
fill={
mode === "add"
? "rgba(255,237,213, 1)"
: "rgba(254, 226, 226, 1)"
}
stroke={mode === "add" ? "#f97316" : "#e11d48"}
strokeWidth="2"
/>
{mode === "add" && (
// Semicircle on TOP
<path
d={`M 0 ${-displayH} A ${displayR} ${displayR} 0 0 1 ${displayW} ${-displayH} Z`}
fill="rgba(255,237,213, 1)"
stroke="#f97316"
strokeWidth="2"
transform={`translate(0,0)`}
/>
)}
{mode === "add" && (
// Hide the seam line
<line
x1="2"
y1={-displayH}
x2={displayW - 2}
y2={-displayH}
stroke="rgba(255,237,213, 1)"
strokeWidth="4"
/>
)}
{mode === "subtract" && (
// Semicircle Cutting INTO top
<path
d={`M 0 ${-displayH} A ${displayR} ${displayR} 0 0 0 ${displayW} ${-displayH} Z`}
fill="white"
stroke="#e11d48"
strokeWidth="2"
strokeDasharray="4,4"
/>
)}
{/* Labels */}
<text
x={displayW / 2}
y={-displayH / 2}
textAnchor="middle"
className="font-bold fill-slate-500 opacity-50 text-xl"
>
Rect
</text>
{mode === "add" && (
<text
x={displayW / 2}
y={-displayH - displayR / 2}
textAnchor="middle"
className="font-bold fill-orange-600 text-sm"
>
Semicircle
</text>
)}
{mode === "subtract" && (
<text
x={displayW / 2}
y={-displayH + displayR / 2}
textAnchor="middle"
className="font-bold fill-rose-600 text-sm"
>
Hole
</text>
)}
</g>
</svg>
</div>
<div className="grid grid-cols-2 gap-8 w-full max-w-2xl">
<div>
<label className="text-xs font-bold text-slate-400 uppercase">
Width (Diameter)
</label>
<input
type="range"
min="4"
max="14"
step="2"
value={width}
onChange={(e) => setWidth(parseInt(e.target.value))}
className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-slate-600 mt-2"
/>
<div className="text-right font-mono font-bold text-slate-700">
{width}
</div>
</div>
<div>
<label className="text-xs font-bold text-slate-400 uppercase">
Height
</label>
<input
type="range"
min="4"
max="12"
step="1"
value={height}
onChange={(e) => setHeight(parseInt(e.target.value))}
className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-slate-600 mt-2"
/>
<div className="text-right font-mono font-bold text-slate-700">
{height}
</div>
</div>
</div>
<div className="mt-8 p-4 bg-slate-50 rounded-xl border border-slate-200 w-full max-w-2xl">
<div className="flex justify-between items-center mb-4">
<span className="font-bold text-slate-700">Calculation</span>
<span
className={`px-2 py-1 rounded text-xs font-bold uppercase ${mode === "add" ? "bg-orange-100 text-orange-800" : "bg-rose-100 text-rose-800"}`}
>
{mode === "add" ? "Sum" : "Difference"}
</span>
</div>
<div className="font-mono text-lg space-y-2">
<div className="flex justify-between">
<span className="text-slate-500">Rectangle Area (w×h)</span>
<span>
{width} × {height} = <strong>{rectArea}</strong>
</span>
</div>
<div className="flex justify-between">
<span className="text-slate-500">Semicircle Area (½πr²)</span>
<span>
½ × π × {radius}² <strong>{semiArea.toFixed(1)}</strong>
</span>
</div>
<div className="border-t border-slate-300 my-2 pt-2 flex justify-between font-bold text-xl">
<span>Total Area</span>
<span
className={mode === "add" ? "text-orange-600" : "text-rose-600"}
>
{totalArea.toFixed(1)}
</span>
</div>
</div>
</div>
</div>
);
};
export default CompositeAreaWidget;

View File

@ -0,0 +1,255 @@
import React, { useState } from "react";
const CompositeSolidsWidget: React.FC = () => {
const [isMerged, setIsMerged] = useState(false);
const [w, setW] = useState(60);
const [h, setH] = useState(80);
const [d, setD] = useState(60);
// Surface Area Calcs
const singleSA = 2 * (w * h + w * d + h * d);
const hiddenFaceArea = d * h;
const totalSeparateSA = singleSA * 2;
const mergedSA = totalSeparateSA - 2 * hiddenFaceArea;
// Helper to generate a face style
const getFaceStyle = (
width: number,
height: number,
transform: string,
color: string,
) => ({
width: `${width}px`,
height: `${height}px`,
position: "absolute" as const,
left: "50%",
top: "50%",
marginLeft: `-${width / 2}px`,
marginTop: `-${height / 2}px`,
transform: transform,
backgroundColor: color,
border: "1px solid rgba(255,255,255,0.3)",
display: "flex",
alignItems: "center",
justifyContent: "center",
backfaceVisibility: "hidden" as const, // Hide backfaces for cleaner look if opaque
transition: "all 0.5s",
});
// Prism Component
const Prism = ({
positionX,
baseHue,
highlightSide, // 'left' or 'right' indicates the face to highlight red
}: {
positionX: number;
baseHue: "indigo" | "sky";
highlightSide?: "left" | "right";
}) => {
// Define shades based on hue
// Lighting: Top is lightest, Front is base, Side is darkest
const colors =
baseHue === "indigo"
? { top: "#818cf8", front: "#6366f1", side: "#4f46e5" } // Indigo 400, 500, 600
: { top: "#38bdf8", front: "#0ea5e9", side: "#0284c7" }; // Sky 400, 500, 600
const hiddenColor = "#f43f5e"; // Rose 500
return (
<div
className="absolute top-0 left-0 transition-all duration-700 ease-in-out transform-style-3d"
style={{ transform: `translateX(${positionX}px)` }}
>
{/* Front (w x h) */}
<div
style={getFaceStyle(w, h, `translateZ(${d / 2}px)`, colors.front)}
/>
{/* Back (w x h) - usually hidden but good for completeness */}
<div
style={getFaceStyle(
w,
h,
`rotateY(180deg) translateZ(${d / 2}px)`,
colors.front,
)}
/>
{/* Right (d x h) */}
<div
style={getFaceStyle(
d,
h,
`rotateY(90deg) translateZ(${w / 2}px)`,
highlightSide === "right" ? hiddenColor : colors.side,
)}
>
{highlightSide === "right" && (
<span className="text-white font-bold text-xs rotate-90 tracking-widest">
FACE
</span>
)}
</div>
{/* Left (d x h) */}
<div
style={getFaceStyle(
d,
h,
`rotateY(-90deg) translateZ(${w / 2}px)`,
highlightSide === "left" ? hiddenColor : colors.side,
)}
>
{highlightSide === "left" && (
<span className="text-white font-bold text-xs -rotate-90 tracking-widest">
FACE
</span>
)}
</div>
{/* Top (w x d) */}
<div
style={getFaceStyle(
w,
d,
`rotateX(90deg) translateZ(${h / 2}px)`,
colors.top,
)}
/>
{/* Bottom (w x d) */}
<div
style={getFaceStyle(
w,
d,
`rotateX(-90deg) translateZ(${h / 2}px)`,
colors.side,
)}
/>
</div>
);
};
// Gap Logic
const gap = isMerged ? 0 : 40;
const posLeft = -(w / 2 + gap / 2);
const posRight = w / 2 + gap / 2;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200 flex flex-col items-center">
<div className="flex justify-between w-full items-center mb-8">
<h3 className="text-lg font-bold text-slate-800">
The "Hidden Face" Trap
</h3>
<button
onClick={() => setIsMerged(!isMerged)}
className={`px-6 py-2 rounded-full font-bold shadow-sm transition-all text-sm ${isMerged ? "bg-slate-200 text-slate-700 hover:bg-slate-300" : "bg-indigo-600 text-white hover:bg-indigo-700"}`}
>
{isMerged ? "Separate Prisms" : "Glue Together"}
</button>
</div>
{/* 3D Scene */}
<div className="relative h-72 w-full flex items-center justify-center perspective-1000 overflow-visible mb-8">
{/* Container rotated for Isometric-ish view */}
<div
className="relative transform-style-3d transition-transform duration-700"
style={{ transform: "rotateX(-15deg) rotateY(35deg)" }}
>
{/* Left Prism (Indigo) - Right face hidden */}
<Prism positionX={posLeft} baseHue="indigo" highlightSide="right" />
{/* Right Prism (Sky) - Left face hidden */}
<Prism positionX={posRight} baseHue="sky" highlightSide="left" />
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 w-full">
<div className="space-y-4">
<div className="bg-slate-50 p-4 rounded-lg border border-slate-200">
<h4 className="text-xs font-bold text-slate-400 uppercase mb-3">
Dimensions
</h4>
<div className="space-y-4">
<div>
<div className="flex justify-between text-xs font-bold text-slate-600 mb-1">
<span>Width (w)</span> <span>{w}</span>
</div>
<input
type="range"
min="40"
max="80"
value={w}
onChange={(e) => setW(parseInt(e.target.value))}
className="w-full h-1 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-indigo-600"
/>
</div>
<div>
<div className="flex justify-between text-xs font-bold text-slate-600 mb-1">
<span>Height (h)</span> <span>{h}</span>
</div>
<input
type="range"
min="40"
max="100"
value={h}
onChange={(e) => setH(parseInt(e.target.value))}
className="w-full h-1 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-indigo-600"
/>
</div>
<div>
<div className="flex justify-between text-xs font-bold text-slate-600 mb-1">
<span>Depth (d)</span> <span>{d}</span>
</div>
<input
type="range"
min="40"
max="80"
value={d}
onChange={(e) => setD(parseInt(e.target.value))}
className="w-full h-1 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-indigo-600"
/>
</div>
</div>
</div>
</div>
<div className="space-y-4">
<div
className={`p-5 rounded-xl border transition-colors ${isMerged ? "bg-indigo-50 border-indigo-200" : "bg-slate-50 border-slate-200"}`}
>
<div className="text-xs uppercase font-bold text-slate-500 mb-2">
Total Surface Area
</div>
<div className="text-4xl font-mono font-bold text-slate-800 tracking-tight">
{isMerged ? mergedSA : totalSeparateSA}
</div>
<div className="text-sm mt-2 text-slate-600 font-medium">
{isMerged
? "⬇ Area decreased (Faces Hidden)"
: "Sum of 2 separated prisms"}
</div>
</div>
<div
className={`p-4 rounded-lg border flex justify-between items-center transition-colors ${isMerged ? "bg-rose-50 border-rose-200 opacity-50" : "bg-rose-50 border-rose-200"}`}
>
<span className="text-xs font-bold text-rose-800 uppercase">
Hidden Area Calculation
</span>
<div className="text-right">
<div className="font-mono font-bold text-rose-600 text-lg">
2 × ({d}×{h})
</div>
<div className="text-xs text-rose-700/70 font-bold">
= {2 * hiddenFaceArea} lost
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default CompositeSolidsWidget;

View File

@ -0,0 +1,98 @@
import React, { useState } from 'react';
const ConfidenceIntervalWidget: React.FC = () => {
const [meanA, setMeanA] = useState(46);
const [moeA, setMoeA] = useState(4);
const [meanB, setMeanB] = useState(52);
const [moeB, setMoeB] = useState(5);
const minA = meanA - moeA;
const maxA = meanA + moeA;
const minB = meanB - moeB;
const maxB = meanB + moeB;
// Overlap Logic
const overlap = Math.max(0, Math.min(maxA, maxB) - Math.max(minA, minB));
const isOverlapping = overlap > 0;
// Visual Scale (Range 30 to 70)
const scale = (val: number) => ((val - 30) / 40) * 100;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="mb-8 relative h-32 bg-slate-50 rounded-lg border border-slate-100">
{/* Grid lines */}
{[35, 40, 45, 50, 55, 60, 65].map(v => (
<div key={v} className="absolute top-0 bottom-0 border-r border-slate-200 text-xs text-slate-300 pt-2" style={{ left: `${scale(v)}%` }}>
<span className="absolute -bottom-5 -translate-x-1/2">{v}</span>
</div>
))}
{/* Interval A */}
<div className="absolute top-8 h-4 bg-indigo-500/20 border-l-2 border-r-2 border-indigo-500 rounded flex items-center justify-center group"
style={{ left: `${scale(minA)}%`, width: `${scale(maxA) - scale(minA)}%` }}>
<div className="w-1.5 h-1.5 bg-indigo-600 rounded-full"></div> {/* Point Estimate */}
<div className="absolute -top-6 text-xs font-bold text-indigo-600 whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity">
Group A: {minA} to {maxA}
</div>
</div>
{/* Interval B */}
<div className="absolute top-20 h-4 bg-emerald-500/20 border-l-2 border-r-2 border-emerald-500 rounded flex items-center justify-center group"
style={{ left: `${scale(minB)}%`, width: `${scale(maxB) - scale(minB)}%` }}>
<div className="w-1.5 h-1.5 bg-emerald-600 rounded-full"></div>
<div className="absolute -top-6 text-xs font-bold text-emerald-600 whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity">
Group B: {minB} to {maxB}
</div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mb-6">
<div className="p-4 bg-indigo-50 rounded-lg border border-indigo-100">
<h4 className="font-bold text-indigo-900 mb-2">Group A</h4>
<div className="space-y-3">
<div className="flex justify-between text-sm">
<span>Mean</span>
<input type="range" min="35" max="65" value={meanA} onChange={e => setMeanA(parseInt(e.target.value))} className="w-24 accent-indigo-600"/>
<span className="font-bold">{meanA}%</span>
</div>
<div className="flex justify-between text-sm">
<span>Margin of Error</span>
<input type="range" min="1" max="10" value={moeA} onChange={e => setMoeA(parseInt(e.target.value))} className="w-24 accent-indigo-600"/>
<span className="font-bold">±{moeA}</span>
</div>
</div>
</div>
<div className="p-4 bg-emerald-50 rounded-lg border border-emerald-100">
<h4 className="font-bold text-emerald-900 mb-2">Group B</h4>
<div className="space-y-3">
<div className="flex justify-between text-sm">
<span>Mean</span>
<input type="range" min="35" max="65" value={meanB} onChange={e => setMeanB(parseInt(e.target.value))} className="w-24 accent-emerald-600"/>
<span className="font-bold">{meanB}%</span>
</div>
<div className="flex justify-between text-sm">
<span>Margin of Error</span>
<input type="range" min="1" max="10" value={moeB} onChange={e => setMoeB(parseInt(e.target.value))} className="w-24 accent-emerald-600"/>
<span className="font-bold">±{moeB}</span>
</div>
</div>
</div>
</div>
<div className={`p-4 rounded-xl border-l-4 ${isOverlapping ? 'bg-amber-50 border-amber-400 text-amber-900' : 'bg-green-50 border-green-500 text-green-900'}`}>
<h4 className="font-bold text-lg mb-1">
{isOverlapping ? "⚠️ Conclusion: Inconclusive" : "✅ Conclusion: Strong Evidence"}
</h4>
<p className="text-sm">
{isOverlapping
? `The intervals overlap (between ${Math.max(minA, minB)} and ${Math.min(maxA, maxB)}). We cannot rule out that the true means are equal.`
: "The intervals do not overlap. It is highly likely that there is a real difference between the groups."}
</p>
</div>
</div>
);
};
export default ConfidenceIntervalWidget;

View File

@ -0,0 +1,175 @@
import React, { useState } from 'react';
import { CheckCircle2, RotateCcw, ChevronRight } from 'lucide-react';
export interface VocabOption {
id: string;
definition: string;
isCorrect: boolean;
elimReason: string; // why wrong (for eliminated options) or why right (for correct option)
}
export interface VocabExercise {
sentence: string;
word: string; // the target word — will be highlighted
question: string;
options: VocabOption[];
}
interface ContextEliminationWidgetProps {
exercises: VocabExercise[];
accentColor?: string;
}
export default function ContextEliminationWidget({ exercises, accentColor = 'rose' }: ContextEliminationWidgetProps) {
const [activeEx, setActiveEx] = useState(0);
const [eliminated, setEliminated] = useState<Set<string>>(new Set());
const [revealed, setRevealed] = useState(false);
const [triedCorrect, setTriedCorrect] = useState(false);
const exercise = exercises[activeEx];
const wrongIds = exercise.options.filter(o => !o.isCorrect).map(o => o.id);
const allWrongEliminated = wrongIds.every(id => eliminated.has(id));
const eliminate = (id: string) => {
const opt = exercise.options.find(o => o.id === id)!;
if (opt.isCorrect) {
setTriedCorrect(true);
setTimeout(() => setTriedCorrect(false), 1500);
} else {
const newElim = new Set([...eliminated, id]);
setEliminated(newElim);
if (wrongIds.every(wid => newElim.has(wid))) {
setRevealed(true);
}
}
};
const reset = () => { setEliminated(new Set()); setRevealed(false); setTriedCorrect(false); };
const switchEx = (i: number) => { setActiveEx(i); setEliminated(new Set()); setRevealed(false); setTriedCorrect(false); };
// Highlight the target word in the sentence
const renderSentence = () => {
const idx = exercise.sentence.toLowerCase().indexOf(exercise.word.toLowerCase());
if (idx === -1) return <>{exercise.sentence}</>;
return (
<>
{exercise.sentence.slice(0, idx)}
<mark className={`bg-${accentColor}-200 text-${accentColor}-900 font-bold px-0.5 rounded not-italic`}>
{exercise.sentence.slice(idx, idx + exercise.word.length)}
</mark>
{exercise.sentence.slice(idx + exercise.word.length)}
</>
);
};
return (
<div className="rounded-2xl border border-gray-200 bg-white overflow-hidden shadow-sm">
{/* Tab strip */}
{exercises.length > 1 && (
<div className="flex border-b border-gray-200 bg-gray-50 overflow-x-auto">
{exercises.map((_, i) => (
<button
key={i}
onClick={() => switchEx(i)}
className={`px-4 py-2.5 text-sm font-medium whitespace-nowrap transition-colors ${
i === activeEx
? `bg-white border-b-2 border-${accentColor}-600 text-${accentColor}-700`
: 'text-gray-500 hover:text-gray-700'
}`}
>
Word {i + 1}
</button>
))}
</div>
)}
{/* Sentence in context */}
<div className={`px-5 py-4 border-b border-gray-100 bg-${accentColor}-50`}>
<p className={`text-xs font-semibold uppercase tracking-wider text-${accentColor}-500 mb-2`}>Sentence in Context</p>
<p className="text-gray-700 italic leading-relaxed text-sm">{renderSentence()}</p>
</div>
{/* Question + instruction */}
<div className="px-5 pt-4 pb-2">
<p className="font-medium text-gray-800 text-sm mb-1">{exercise.question}</p>
<p className="text-xs text-gray-400 italic">
{revealed
? 'You found it! The correct definition is highlighted.'
: 'Click "Eliminate" on definitions that don\'t fit the context. Work by elimination.'}
</p>
</div>
{/* Tried to eliminate correct option flash */}
{triedCorrect && (
<div className="mx-5 mb-2 px-3 py-2 bg-amber-50 border border-amber-200 rounded-xl text-xs text-amber-700 font-medium">
Can't eliminate that one — it fits the context too well!
</div>
)}
{/* Options */}
<div className="px-5 py-3 space-y-2">
{exercise.options.map(opt => {
const isElim = eliminated.has(opt.id);
const isAnswer = opt.isCorrect && revealed;
let wrapCls = 'border-gray-200 bg-white';
if (isAnswer) wrapCls = 'border-green-400 bg-green-50';
else if (isElim) wrapCls = 'border-gray-100 bg-gray-50';
return (
<div
key={opt.id}
className={`rounded-xl border px-4 py-3 transition-all ${wrapCls} ${isElim ? 'opacity-50' : ''}`}
>
<div className="flex items-start gap-3">
<span className={`text-xs font-bold mt-0.5 shrink-0 ${isElim ? 'text-gray-400' : isAnswer ? 'text-green-700' : 'text-gray-500'}`}>
{opt.id}.
</span>
<div className="flex-1 min-w-0">
<p className={`text-sm leading-snug ${
isElim ? 'text-gray-400 line-through' :
isAnswer ? 'text-green-800 font-semibold' :
'text-gray-700'
}`}>
{opt.definition}
</p>
{isElim && (
<p className="text-xs text-gray-400 mt-0.5 italic">{opt.elimReason}</p>
)}
{isAnswer && (
<p className="text-xs text-green-700 mt-1">✓ {opt.elimReason}</p>
)}
</div>
<div className="shrink-0">
{isAnswer && <CheckCircle2 className="w-5 h-5 text-green-500" />}
{!isElim && !isAnswer && !revealed && (
<button
onClick={() => eliminate(opt.id)}
className="text-xs font-semibold text-red-500 hover:text-red-700 hover:bg-red-50 px-2.5 py-1 rounded-lg transition-colors border border-red-200 hover:border-red-300"
>
Eliminate ✗
</button>
)}
</div>
</div>
</div>
);
})}
</div>
<div className="px-5 pb-5 flex items-center gap-3">
<button onClick={reset} className="flex items-center gap-1.5 text-sm text-gray-500 hover:text-gray-700 transition-colors">
<RotateCcw className="w-3.5 h-3.5" /> Reset
</button>
{revealed && activeEx < exercises.length - 1 && (
<button
onClick={() => switchEx(activeEx + 1)}
className={`ml-auto flex items-center gap-1.5 text-sm font-semibold text-${accentColor}-700 hover:text-${accentColor}-900 transition-colors`}
>
Next word <ChevronRight className="w-4 h-4" />
</button>
)}
</div>
</div>
);
}

View File

@ -0,0 +1,186 @@
import React, { useRef, useState, useEffect } from 'react';
import { scaleToSvg, scaleFromSvg, round, calculateDistanceSquared } from '../utils/math';
import { CircleState, Point } from '../types';
interface CoordinatePlaneProps {
circle: CircleState;
point?: Point | null;
onPointClick?: (p: Point) => void;
interactive?: boolean;
showDistance?: boolean;
mode?: 'view' | 'place_point';
}
const CoordinatePlane: React.FC<CoordinatePlaneProps> = ({
circle,
point,
onPointClick,
showDistance = false,
mode = 'view'
}) => {
const svgRef = useRef<SVGSVGElement>(null);
const [hoverPoint, setHoverPoint] = useState<Point | null>(null);
// Viewport settings
const width = 400;
const height = 400;
const range = 10; // -10 to 10
const tickSpacing = 1;
// Scales
const toX = (val: number) => scaleToSvg(val, -range, range, 0, width);
const toY = (val: number) => scaleToSvg(val, range, -range, 0, height); // Inverted Y for SVG
const fromX = (px: number) => scaleFromSvg(px, -range, range, 0, width);
const fromY = (px: number) => scaleFromSvg(px, range, -range, 0, height);
const cx = toX(circle.h);
const cy = toY(circle.k);
// Radius in pixels (assuming uniform aspect ratio)
const rPx = toX(circle.r) - toX(0);
const handleMouseMove = (e: React.MouseEvent) => {
if (mode !== 'place_point' || !svgRef.current) return;
const rect = svgRef.current.getBoundingClientRect();
const rawX = e.clientX - rect.left;
const rawY = e.clientY - rect.top;
// Snap to nearest 0.5 for cleaner UX
const graphX = Math.round(fromX(rawX) * 2) / 2;
const graphY = Math.round(fromY(rawY) * 2) / 2;
setHoverPoint({ x: graphX, y: graphY });
};
const handleClick = () => {
if (mode === 'place_point' && hoverPoint && onPointClick) {
onPointClick(hoverPoint);
}
};
// Generate grid lines
const ticks = [];
for (let i = -range; i <= range; i += tickSpacing) {
if (i === 0) continue; // Skip axes (drawn separately)
ticks.push(i);
}
const dSquared = point ? calculateDistanceSquared(point.x, point.y, circle.h, circle.k) : 0;
const isInside = dSquared < circle.r * circle.r;
const isOn = Math.abs(dSquared - circle.r * circle.r) < 0.01;
const pointColor = isOn ? 'text-yellow-600' : isInside ? 'text-green-600' : 'text-red-600';
const pointFill = isOn ? '#ca8a04' : isInside ? '#16a34a' : '#dc2626';
return (
<div className="flex flex-col items-center">
<div className="relative shadow-lg rounded-xl overflow-hidden bg-white border border-slate-200">
<svg
ref={svgRef}
width={width}
height={height}
onMouseMove={handleMouseMove}
onMouseLeave={() => setHoverPoint(null)}
onClick={handleClick}
className={`${mode === 'place_point' ? 'cursor-crosshair' : 'cursor-default'}`}
>
{/* Grid Background */}
{ticks.map(t => (
<React.Fragment key={t}>
<line x1={toX(t)} y1={0} x2={toX(t)} y2={height} stroke="#e2e8f0" strokeWidth="1" />
<line x1={0} y1={toY(t)} x2={width} y2={toY(t)} stroke="#e2e8f0" strokeWidth="1" />
</React.Fragment>
))}
{/* Axes */}
<line x1={toX(0)} y1={0} x2={toX(0)} y2={height} stroke="#64748b" strokeWidth="2" />
<line x1={0} y1={toY(0)} x2={width} y2={toY(0)} stroke="#64748b" strokeWidth="2" />
{/* Circle */}
<circle
cx={cx}
cy={cy}
r={Math.abs(rPx)}
fill="rgba(99, 102, 241, 0.1)"
stroke="#4f46e5"
strokeWidth="3"
className="transition-all duration-300 ease-out"
/>
{/* Center Point */}
<circle cx={cx} cy={cy} r={4} fill="#4f46e5" />
<text x={cx + 8} y={cy - 8} fontSize="12" fill="#4f46e5" fontWeight="bold">Center ({circle.h}, {circle.k})</text>
{/* Radius Line (only if distance line is not active to avoid clutter) */}
{!point && (
<line
x1={cx}
y1={cy}
x2={cx + rPx}
y2={cy}
stroke="#4f46e5"
strokeWidth="2"
strokeDasharray="5,5"
/>
)}
{!point && (
<text x={cx + rPx/2} y={cy - 5} fontSize="12" fill="#4f46e5">r = {circle.r}</text>
)}
{/* Placed Point */}
{point && (
<>
<line
x1={cx}
y1={cy}
x2={toX(point.x)}
y2={toY(point.y)}
stroke="#94a3b8"
strokeWidth="2"
strokeDasharray="4,4"
/>
<circle cx={toX(point.x)} cy={toY(point.y)} r={6} fill={pointFill} stroke="white" strokeWidth="2" />
<text x={toX(point.x) + 8} y={toY(point.y) - 8} fontSize="12" fontWeight="bold" fill={pointFill}>
({point.x}, {point.y})
</text>
</>
)}
{/* Hover Ghost Point */}
{mode === 'place_point' && hoverPoint && !point && (
<circle cx={toX(hoverPoint.x)} cy={toY(hoverPoint.y)} r={4} fill="rgba(0,0,0,0.3)" />
)}
</svg>
<div className="absolute bottom-2 left-2 text-xs text-slate-400 bg-white/80 px-2 py-1 rounded">
1 unit = {width / (range * 2)}px
</div>
</div>
{/* Info Panel below graph */}
{point && showDistance && (
<div className={`mt-4 p-4 rounded-lg border-l-4 w-full max-w-md bg-white shadow-sm transition-colors ${
isOn ? 'border-yellow-500 bg-yellow-50' :
isInside ? 'border-green-500 bg-green-50' :
'border-red-500 bg-red-50'
}`}>
<div className="flex justify-between items-center mb-2">
<span className="font-bold text-slate-700">Distance Check:</span>
<span className={`px-2 py-0.5 rounded text-sm font-bold uppercase ${
isOn ? 'bg-yellow-200 text-yellow-800' :
isInside ? 'bg-green-200 text-green-800' :
'bg-red-200 text-red-800'
}`}>
{isOn ? 'On Circle' : isInside ? 'Inside' : 'Outside'}
</span>
</div>
<div className="font-mono text-sm space-y-1">
<p>d² = (x - h)² + (y - k)²</p>
<p>d² = ({point.x} - {circle.h})² + ({point.y} - {circle.k})²</p>
<p>d² = {round(calculateDistanceSquared(point.x, point.y, circle.h, circle.k))} <span className="mx-2 text-slate-400">vs</span> r² = {circle.r * circle.r}</p>
</div>
</div>
)}
</div>
);
};
export default CoordinatePlane;

View File

@ -0,0 +1,443 @@
import React, { useState } from 'react';
import { CheckCircle2, XCircle, RotateCcw } from 'lucide-react';
// ── Types ──────────────────────────────────────────────────────────────────
export type Verdict = 'supported' | 'contradicted' | 'neither';
export interface ChartSeries {
name: string;
data: { label: string; value: number }[];
}
export interface ChartData {
type: 'bar' | 'line';
title: string;
yLabel?: string;
xLabel?: string;
source?: string;
unit?: string; // e.g. '%', '°C', 'min'
series: ChartSeries[];
}
export interface DataClaim {
text: string;
verdict: Verdict;
explanation: string;
}
export interface DataExercise {
title: string;
chart: ChartData;
claims: DataClaim[];
}
// ── Chart palette ──────────────────────────────────────────────────────────
const PALETTE = ['#3b82f6', '#8b5cf6', '#f97316', '#10b981', '#ef4444', '#ec4899'];
// ── BarChart ───────────────────────────────────────────────────────────────
function BarChart({ chart }: { chart: ChartData }) {
const [hovered, setHovered] = useState<{ si: number; pi: number } | null>(null);
const labels = chart.series[0].data.map(d => d.label);
const allValues = chart.series.flatMap(s => s.data.map(d => d.value));
const maxVal = Math.max(...allValues);
// Round up max to nearest 10 for cleaner y-axis
const yMax = Math.ceil(maxVal / 10) * 10;
const yTicks = [0, yMax * 0.25, yMax * 0.5, yMax * 0.75, yMax];
const chartH = 180; // px height of bar area
return (
<div className="px-2">
<p className="text-xs font-semibold text-gray-600 text-center mb-4">{chart.title}</p>
<div className="flex gap-2">
{/* Y-axis */}
<div className="flex flex-col-reverse justify-between items-end pr-1" style={{ height: chartH, minWidth: 32 }}>
{yTicks.map(t => (
<span key={t} className="text-[10px] text-gray-400 leading-none">{t}{chart.unit ?? ''}</span>
))}
</div>
{/* Bar groups */}
<div className="flex-1 flex items-end gap-2 border-b border-l border-gray-300" style={{ height: chartH }}>
{labels.map((label, pi) => (
<div key={pi} className="flex-1 flex flex-col items-center gap-0">
{/* Bar group */}
<div className="w-full flex items-end gap-0.5" style={{ height: chartH - 2 }}>
{chart.series.map((s, si) => {
const val = s.data[pi].value;
const heightPct = (val / yMax) * 100;
const isHov = hovered?.si === si && hovered?.pi === pi;
return (
<div
key={si}
className="relative flex-1 rounded-t-sm transition-all duration-150 cursor-pointer"
style={{
height: `${heightPct}%`,
backgroundColor: isHov
? PALETTE[si % PALETTE.length] + 'dd'
: PALETTE[si % PALETTE.length] + 'cc',
outline: isHov ? `2px solid ${PALETTE[si % PALETTE.length]}` : 'none',
}}
onMouseEnter={() => setHovered({ si, pi })}
onMouseLeave={() => setHovered(null)}
>
{/* Value label on hover */}
{isHov && (
<div
className="absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-1.5 py-0.5 rounded text-[10px] font-bold text-white whitespace-nowrap z-10 pointer-events-none"
style={{ backgroundColor: PALETTE[si % PALETTE.length] }}
>
{val}{chart.unit ?? ''}
</div>
)}
</div>
);
})}
</div>
</div>
))}
</div>
</div>
{/* X-axis labels */}
<div className="flex gap-2 ml-10 mt-1">
{labels.map((label, i) => (
<div key={i} className="flex-1 text-center text-[10px] text-gray-500 leading-tight">{label}</div>
))}
</div>
{chart.xLabel && <p className="text-[10px] text-gray-400 text-center mt-1">{chart.xLabel}</p>}
{/* Legend */}
{chart.series.length > 1 && (
<div className="flex flex-wrap gap-3 mt-3 justify-center">
{chart.series.map((s, si) => (
<div key={si} className="flex items-center gap-1.5 text-xs text-gray-600">
<div className="w-3 h-3 rounded-sm" style={{ backgroundColor: PALETTE[si % PALETTE.length] }} />
{s.name}
</div>
))}
</div>
)}
{/* Hover info bar */}
{hovered && (
<div className="mt-3 text-xs text-center text-gray-600 bg-gray-50 rounded-lg py-1.5 px-3">
<span className="font-semibold" style={{ color: PALETTE[hovered.si % PALETTE.length] }}>
{chart.series[hovered.si].name}
</span>
{' — '}
{chart.series[0].data[hovered.pi].label}: <span className="font-semibold">
{chart.series[hovered.si].data[hovered.pi].value}{chart.unit ?? ''}
</span>
</div>
)}
{chart.source && <p className="text-[10px] text-gray-400 text-center mt-2">Source: {chart.source}</p>}
</div>
);
}
// ── LineChart ──────────────────────────────────────────────────────────────
function LineChart({ chart }: { chart: ChartData }) {
const [hovered, setHovered] = useState<{ si: number; pi: number } | null>(null);
const W = 480, H = 200;
const PAD = { top: 20, right: 20, bottom: 36, left: 48 };
const cW = W - PAD.left - PAD.right;
const cH = H - PAD.top - PAD.bottom;
const allValues = chart.series.flatMap(s => s.data.map(d => d.value));
const minVal = Math.min(...allValues);
const maxVal = Math.max(...allValues);
const spread = maxVal - minVal || 1;
// Add 10% padding on y-axis
const yPad = spread * 0.15;
const yMin = minVal - yPad;
const yMax = maxVal + yPad;
const yRange = yMax - yMin;
const labels = chart.series[0].data.map(d => d.label);
const xStep = cW / (labels.length - 1);
const xPos = (i: number) => PAD.left + i * xStep;
const yPos = (v: number) => PAD.top + cH - ((v - yMin) / yRange) * cH;
// Y-axis ticks: 5 evenly spaced
const yTicks = Array.from({ length: 5 }, (_, i) => minVal + ((maxVal - minVal) / 4) * i);
return (
<div>
<p className="text-xs font-semibold text-gray-600 text-center mb-2">{chart.title}</p>
<div className="overflow-x-auto">
<svg viewBox={`0 0 ${W} ${H}`} className="w-full" style={{ maxHeight: 220 }}>
{/* Grid lines */}
{yTicks.map((t, i) => {
const y = yPos(t);
return (
<g key={i}>
<line x1={PAD.left} x2={W - PAD.right} y1={y} y2={y} stroke="#e5e7eb" strokeWidth="1" />
<text x={PAD.left - 4} y={y + 3.5} textAnchor="end" fontSize="9" fill="#9ca3af">
{t % 1 === 0 ? t : t.toFixed(2)}{chart.unit ?? ''}
</text>
</g>
);
})}
{/* Lines + dots */}
{chart.series.map((s, si) => {
const color = PALETTE[si % PALETTE.length];
const pts = s.data.map((d, i) => `${xPos(i)},${yPos(d.value)}`).join(' ');
return (
<g key={si}>
<polyline points={pts} fill="none" stroke={color} strokeWidth="2.5" strokeLinejoin="round" />
{s.data.map((d, pi) => {
const isHov = hovered?.si === si && hovered?.pi === pi;
const cx = xPos(pi);
const cy = yPos(d.value);
return (
<g key={pi}>
<circle
cx={cx} cy={cy} r={isHov ? 7 : 5}
fill={color} stroke="white" strokeWidth="2"
style={{ cursor: 'pointer', transition: 'r 0.1s' }}
onMouseEnter={() => setHovered({ si, pi })}
onMouseLeave={() => setHovered(null)}
/>
{isHov && (
<>
<rect
x={cx - 28} y={cy - 26} width="56" height="18"
rx="4" fill="#1f2937"
/>
<text x={cx} y={cy - 13} textAnchor="middle" fontSize="10" fill="white" fontWeight="bold">
{d.value}{chart.unit ?? ''}
</text>
</>
)}
</g>
);
})}
</g>
);
})}
{/* X-axis labels */}
{labels.map((label, i) => (
<text key={i} x={xPos(i)} y={H - PAD.bottom + 14} textAnchor="middle" fontSize="9.5" fill="#6b7280">
{label}
</text>
))}
{/* Axes */}
<line x1={PAD.left} x2={PAD.left} y1={PAD.top} y2={H - PAD.bottom} stroke="#d1d5db" strokeWidth="1.5" />
<line x1={PAD.left} x2={W - PAD.right} y1={H - PAD.bottom} y2={H - PAD.bottom} stroke="#d1d5db" strokeWidth="1.5" />
{/* Y-axis label */}
{chart.yLabel && (
<text
x={12} y={H / 2}
transform={`rotate(-90, 12, ${H / 2})`}
textAnchor="middle" fontSize="9" fill="#9ca3af"
>
{chart.yLabel}
</text>
)}
</svg>
</div>
{/* Legend */}
{chart.series.length > 1 && (
<div className="flex flex-wrap gap-3 mt-1 justify-center">
{chart.series.map((s, si) => (
<div key={si} className="flex items-center gap-1.5 text-xs text-gray-600">
<div className="w-5 h-0.5" style={{ backgroundColor: PALETTE[si % PALETTE.length] }} />
{s.name}
</div>
))}
</div>
)}
{/* Hover tooltip */}
{hovered && (
<div className="mt-2 text-xs text-center text-gray-600 bg-gray-50 rounded-lg py-1.5 px-3">
<span className="font-semibold" style={{ color: PALETTE[hovered.si % PALETTE.length] }}>
{chart.series[hovered.si].name}
</span>
{' · '}
{chart.series[0].data[hovered.pi].label}: <span className="font-semibold">
{chart.series[hovered.si].data[hovered.pi].value}{chart.unit ?? ''}
</span>
</div>
)}
{chart.source && <p className="text-[10px] text-gray-400 text-center mt-2">Source: {chart.source}</p>}
</div>
);
}
// ── Main widget ────────────────────────────────────────────────────────────
const VERDICT_LABELS: Record<Verdict, string> = {
supported: 'Supported by data',
contradicted: 'Contradicted by data',
neither: 'Neither proven nor disproven',
};
interface DataClaimWidgetProps {
exercises: DataExercise[];
accentColor?: string;
}
// Pre-resolved accent classes to avoid Tailwind purge issues
const ACCENT_CLASSES: Record<string, { tab: string; header: string; label: string; btn: string }> = {
amber: { tab: 'border-b-2 border-amber-600 text-amber-700', header: 'bg-amber-50', label: 'text-amber-600', btn: 'bg-amber-600 hover:bg-amber-700' },
teal: { tab: 'border-b-2 border-teal-600 text-teal-700', header: 'bg-teal-50', label: 'text-teal-600', btn: 'bg-teal-600 hover:bg-teal-700' },
purple: { tab: 'border-b-2 border-purple-600 text-purple-700', header: 'bg-purple-50', label: 'text-purple-600', btn: 'bg-purple-600 hover:bg-purple-700' },
fuchsia: { tab: 'border-b-2 border-fuchsia-600 text-fuchsia-700', header: 'bg-fuchsia-50', label: 'text-fuchsia-600', btn: 'bg-fuchsia-600 hover:bg-fuchsia-700' },
};
export default function DataClaimWidget({ exercises, accentColor = 'amber' }: DataClaimWidgetProps) {
const [activeEx, setActiveEx] = useState(0);
const [answers, setAnswers] = useState<Record<number, Verdict>>({});
const [submitted, setSubmitted] = useState(false);
const exercise = exercises[activeEx];
const allAnswered = exercise.claims.every((_, i) => answers[i] !== undefined);
const score = submitted ? exercise.claims.filter((c, i) => answers[i] === c.verdict).length : 0;
const c = ACCENT_CLASSES[accentColor] ?? ACCENT_CLASSES.amber;
const reset = () => { setAnswers({}); setSubmitted(false); };
const switchEx = (i: number) => { setActiveEx(i); setAnswers({}); setSubmitted(false); };
return (
<div className="rounded-2xl border border-gray-200 bg-white overflow-hidden shadow-sm">
{/* Tabs */}
{exercises.length > 1 && (
<div className="flex border-b border-gray-200 bg-gray-50 overflow-x-auto">
{exercises.map((ex, i) => (
<button
key={i}
onClick={() => switchEx(i)}
className={`px-4 py-2.5 text-sm font-medium whitespace-nowrap transition-colors bg-white ${
i === activeEx ? c.tab : 'text-gray-500 hover:text-gray-700'
}`}
>
{ex.title}
</button>
))}
</div>
)}
{/* Chart */}
<div className={`px-5 pt-5 pb-4 border-b border-gray-200 ${c.header}`}>
<p className={`text-xs font-bold uppercase tracking-wider mb-4 ${c.label}`}>Data Source</p>
{exercise.chart.type === 'bar'
? <BarChart chart={exercise.chart} />
: <LineChart chart={exercise.chart} />
}
</div>
{/* Claims */}
<div className="px-5 py-4">
<p className="text-sm text-gray-600 mb-4">
For each claim, decide if the data{' '}
<strong className="text-green-700">supports</strong>,{' '}
<strong className="text-red-600">contradicts</strong>, or{' '}
<strong className="text-gray-600">neither proves nor disproves</strong> it:
</p>
<div className="space-y-4">
{exercise.claims.map((claim, i) => {
const userAnswer = answers[i];
const isCorrect = submitted && userAnswer === claim.verdict;
const isWrong = submitted && userAnswer !== undefined && userAnswer !== claim.verdict;
return (
<div
key={i}
className={`rounded-xl border p-4 transition-all ${
submitted
? isCorrect ? 'border-green-300 bg-green-50'
: isWrong ? 'border-red-200 bg-red-50'
: 'border-gray-200'
: 'border-gray-200'
}`}
>
<p className="text-sm text-gray-800 mb-3">
<span className="font-bold text-gray-400 mr-2">Claim {i + 1}:</span>
{claim.text}
</p>
<div className="flex flex-wrap gap-2">
{(['supported', 'contradicted', 'neither'] as Verdict[]).map(v => {
const isSelected = userAnswer === v;
const isCorrectOpt = submitted && v === claim.verdict;
let cls = 'border-gray-200 text-gray-600 hover:border-gray-400 hover:bg-gray-50';
if (isSelected && !submitted) cls = `border-amber-500 bg-amber-50 text-amber-800 font-semibold`;
if (submitted) {
if (isCorrectOpt) cls = 'border-green-400 bg-green-100 text-green-800 font-semibold';
else if (isSelected) cls = 'border-red-300 bg-red-100 text-red-700';
else cls = 'border-gray-100 text-gray-400';
}
return (
<button
key={v}
disabled={submitted}
onClick={() => setAnswers(prev => ({ ...prev, [i]: v }))}
className={`px-3 py-1.5 rounded-full border text-xs transition-all ${cls}`}
>
{VERDICT_LABELS[v]}
</button>
);
})}
</div>
{submitted && (
<div className="mt-3 pt-2 border-t border-gray-100 flex gap-2">
{isCorrect
? <CheckCircle2 className="w-4 h-4 text-green-600 shrink-0 mt-0.5" />
: <XCircle className="w-4 h-4 text-red-500 shrink-0 mt-0.5" />
}
<p className="text-xs text-gray-600 leading-relaxed">
{!isCorrect && (
<span className="font-semibold text-red-700">Answer: {VERDICT_LABELS[claim.verdict]}. </span>
)}
{claim.explanation}
</p>
</div>
)}
</div>
);
})}
</div>
</div>
{/* Footer */}
<div className="px-5 pb-5">
{!submitted ? (
<button
disabled={!allAnswered}
onClick={() => setSubmitted(true)}
className={`px-5 py-2.5 rounded-full text-sm font-bold text-white transition-colors ${
allAnswered ? c.btn : 'bg-gray-200 text-gray-400 cursor-not-allowed'
}`}
>
Check all answers
</button>
) : (
<div className="flex items-center gap-4">
<p className="text-sm font-semibold text-gray-700">
{score}/{exercise.claims.length} correct
</p>
<button onClick={reset} className="flex items-center gap-1.5 text-sm text-gray-500 hover:text-gray-700 transition-colors">
<RotateCcw className="w-3.5 h-3.5" /> Try again
</button>
</div>
)}
</div>
</div>
);
}

View File

@ -0,0 +1,127 @@
import React, { useState } from 'react';
const DataModifierWidget: React.FC = () => {
const initialData = [10, 12, 13, 15, 16, 18, 20];
const [data, setData] = useState<number[]>(initialData);
const calculateStats = (arr: number[]) => {
const sorted = [...arr].sort((a, b) => a - b);
const sum = sorted.reduce((a, b) => a + b, 0);
const mean = sum / sorted.length;
const min = sorted[0];
const max = sorted[sorted.length - 1];
const range = max - min;
// Median
const mid = Math.floor(sorted.length / 2);
const median = sorted.length % 2 !== 0
? sorted[mid]
: (sorted[mid - 1] + sorted[mid]) / 2;
// SD (Population)
const variance = sorted.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) / sorted.length;
const sd = Math.sqrt(variance);
return { mean, median, range, sd, sorted };
};
const stats = calculateStats(data);
// Operations
const reset = () => setData(initialData);
const addConstant = (k: number) => {
setData(prev => prev.map(n => n + k));
};
const multiplyConstant = (k: number) => {
setData(prev => prev.map(n => n * k));
};
const addOutlier = (val: number) => {
setData(prev => [...prev, val]);
};
// Visual scaling
const minDisplay = Math.min(0, ...data) - 5;
const maxDisplay = Math.max(Math.max(...data), 100) + 10;
const getX = (val: number) => ((val - minDisplay) / (maxDisplay - minDisplay)) * 100;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-6">
{/* Controls */}
<div className="w-full md:w-1/3 space-y-3">
<h4 className="font-bold text-slate-700 mb-2">Apply Transformation</h4>
<button onClick={() => addConstant(5)} className="w-full py-2 px-4 bg-amber-100 hover:bg-amber-200 text-amber-900 rounded-lg font-bold text-sm text-left transition-colors">
+ Add 5 (Shift Right)
</button>
<button onClick={() => multiplyConstant(2)} className="w-full py-2 px-4 bg-amber-100 hover:bg-amber-200 text-amber-900 rounded-lg font-bold text-sm text-left transition-colors">
× Multiply by 2 (Scale)
</button>
<button onClick={() => addOutlier(80)} className="w-full py-2 px-4 bg-rose-100 hover:bg-rose-200 text-rose-900 rounded-lg font-bold text-sm text-left transition-colors border border-rose-200">
Add Outlier (80)
</button>
<button onClick={reset} className="w-full py-2 px-4 bg-slate-100 hover:bg-slate-200 text-slate-600 rounded-lg font-bold text-sm text-left transition-colors mt-4">
Reset Data
</button>
</div>
{/* Visualization */}
<div className="flex-1">
{/* Stats Panel */}
<div className="grid grid-cols-4 gap-2 mb-6 text-center">
<div className="p-2 bg-slate-50 border border-slate-200 rounded">
<div className="text-xs uppercase font-bold text-slate-500">Mean</div>
<div className="font-mono font-bold text-lg text-indigo-600">{stats.mean.toFixed(1)}</div>
</div>
<div className="p-2 bg-slate-50 border border-slate-200 rounded">
<div className="text-xs uppercase font-bold text-slate-500">Median</div>
<div className="font-mono font-bold text-lg text-emerald-600">{stats.median.toFixed(1)}</div>
</div>
<div className="p-2 bg-slate-50 border border-slate-200 rounded">
<div className="text-xs uppercase font-bold text-slate-500">Range</div>
<div className="font-mono font-bold text-lg text-slate-700">{stats.range.toFixed(0)}</div>
</div>
<div className="p-2 bg-slate-50 border border-slate-200 rounded">
<div className="text-xs uppercase font-bold text-slate-500">SD</div>
<div className="font-mono font-bold text-lg text-slate-700">{stats.sd.toFixed(1)}</div>
</div>
</div>
{/* Dot Plot */}
<div className="h-32 relative border-b border-slate-300">
{stats.sorted.map((val, idx) => (
<div
key={idx}
className="absolute w-4 h-4 rounded-full bg-indigo-500 shadow-sm border border-white transform -translate-x-1/2"
style={{ left: `${getX(val)}%`, bottom: '10px' }}
title={`Value: ${val}`}
/>
))}
{/* Mean Marker */}
<div className="absolute top-0 bottom-0 w-0.5 bg-indigo-300 border-l border-dashed border-indigo-500 opacity-60" style={{ left: `${getX(stats.mean)}%` }}>
<span className="absolute -top-6 left-1/2 -translate-x-1/2 text-xs font-bold text-indigo-600 bg-white px-1 rounded shadow-sm"></span>
</div>
{/* Median Marker */}
<div className="absolute top-0 bottom-0 w-0.5 bg-emerald-300 border-l border-dashed border-emerald-500 opacity-60" style={{ left: `${getX(stats.median)}%` }}>
<span className="absolute -bottom-6 left-1/2 -translate-x-1/2 text-xs font-bold text-emerald-600 bg-white px-1 rounded shadow-sm">M</span>
</div>
</div>
<div className="mt-8 text-sm text-slate-500 leading-relaxed bg-slate-50 p-3 rounded">
{data.length > 7 ? (
<span className="text-rose-600 font-bold">Notice how the Mean is pulled towards the outlier, while the Median barely moves!</span>
) : (
"Experiment with adding constants and multipliers to see which stats change."
)}
</div>
</div>
</div>
</div>
);
};
export default DataModifierWidget;

View File

@ -0,0 +1,235 @@
import React, { useState } from 'react';
import { ChevronRight, RotateCcw, CheckCircle2, AlertTriangle, Info } from 'lucide-react';
export interface TreeNode {
id: string;
question: string;
hint?: string;
yesLabel?: string;
noLabel?: string;
yes?: TreeNode;
no?: TreeNode;
result?: string;
resultType?: 'correct' | 'warning' | 'info';
ruleRef?: string;
}
export interface TreeScenario {
label: string; // Short tab label, e.g. "Sentence 1"
sentence: string; // The sentence to analyze
tree: TreeNode;
}
interface DecisionTreeWidgetProps {
scenarios: TreeScenario[];
accentColor?: string;
}
type Answers = Record<string, 'yes' | 'no'>;
/** Walk the tree following answers, return ordered list of [node, answer|null] pairs traversed */
function getPath(root: TreeNode, answers: Answers): Array<{ node: TreeNode; answer: 'yes' | 'no' | null }> {
const path: Array<{ node: TreeNode; answer: 'yes' | 'no' | null }> = [];
let current: TreeNode | undefined = root;
while (current) {
const ans = answers[current.id] ?? null;
path.push({ node: current, answer: ans });
if (ans === null) break; // not answered yet — this is the active node
if (current.result !== undefined) break; // leaf
current = ans === 'yes' ? current.yes : current.no;
}
return path;
}
const RESULT_STYLES = {
correct: {
bg: 'bg-green-50',
border: 'border-green-300',
text: 'text-green-800',
icon: <CheckCircle2 className="w-5 h-5 text-green-600 shrink-0 mt-0.5" />,
},
warning: {
bg: 'bg-amber-50',
border: 'border-amber-300',
text: 'text-amber-800',
icon: <AlertTriangle className="w-5 h-5 text-amber-600 shrink-0 mt-0.5" />,
},
info: {
bg: 'bg-blue-50',
border: 'border-blue-300',
text: 'text-blue-800',
icon: <Info className="w-5 h-5 text-blue-600 shrink-0 mt-0.5" />,
},
};
export default function DecisionTreeWidget({ scenarios, accentColor = 'purple' }: DecisionTreeWidgetProps) {
const [activeScenario, setActiveScenario] = useState(0);
const [answers, setAnswers] = useState<Answers>({});
const scenario = scenarios[activeScenario];
const path = getPath(scenario.tree, answers);
const lastStep = path[path.length - 1];
const isLeaf = lastStep.node.result !== undefined;
const isComplete = isLeaf && lastStep.answer === null; // reached leaf, no more choices needed
// Actually leaf nodes don't have yes/no — they just show result when we arrive
const atLeaf = lastStep.node.result !== undefined;
const handleAnswer = (nodeId: string, ans: 'yes' | 'no') => {
setAnswers(prev => {
// Remove all answers for nodes that come AFTER this one in the current path
const pathIds = path.map(p => p.node.id);
const idx = pathIds.indexOf(nodeId);
const newAnswers: Answers = {};
for (let i = 0; i < idx; i++) {
newAnswers[pathIds[i]] = prev[pathIds[i]]!;
}
newAnswers[nodeId] = ans;
return newAnswers;
});
};
const resetScenario = () => setAnswers({});
const switchScenario = (i: number) => {
setActiveScenario(i);
setAnswers({});
};
return (
<div className="rounded-2xl border border-gray-200 bg-white overflow-hidden shadow-sm">
{/* Scenario tab strip */}
{scenarios.length > 1 && (
<div className="flex border-b border-gray-200 bg-gray-50 overflow-x-auto">
{scenarios.map((sc, i) => (
<button
key={i}
onClick={() => switchScenario(i)}
className={`px-4 py-2.5 text-sm font-medium whitespace-nowrap transition-colors ${
i === activeScenario
? `bg-white border-b-2 border-${accentColor}-600 text-${accentColor}-700`
: 'text-gray-500 hover:text-gray-700'
}`}
>
{sc.label}
</button>
))}
</div>
)}
{/* Sentence under analysis */}
<div className={`px-5 py-4 border-b border-gray-100 bg-${accentColor}-50`}>
<p className={`text-xs font-semibold uppercase tracking-wider text-${accentColor}-500 mb-1`}>Analyze this sentence</p>
<p className="text-gray-800 font-medium italic leading-relaxed">"{scenario.sentence}"</p>
</div>
{/* Breadcrumb path */}
{path.length > 1 && (
<div className="px-5 py-2.5 border-b border-gray-100 bg-gray-50 flex flex-wrap items-center gap-1 text-xs text-gray-500">
{path.map((step, i) => {
if (i === path.length - 1) return null; // last step shown below, not in crumb
const isAnswered = step.answer !== null;
return (
<React.Fragment key={step.node.id}>
<button
onClick={() => {
// Reset from this node forward
const pathIds = path.map(p => p.node.id);
const idx = pathIds.indexOf(step.node.id);
setAnswers(prev => {
const newAnswers: Answers = {};
for (let j = 0; j < idx; j++) newAnswers[pathIds[j]] = prev[pathIds[j]]!;
return newAnswers;
});
}}
className={`px-2 py-0.5 rounded transition-colors ${
isAnswered ? 'text-gray-600 hover:text-gray-900 hover:bg-gray-200' : 'text-gray-400'
}`}
>
{step.node.question.length > 40 ? step.node.question.slice(0, 40) + '…' : step.node.question}
{step.answer && (
<span className={`ml-1 font-semibold ${step.answer === 'yes' ? 'text-green-600' : 'text-red-500'}`}>
{step.answer === 'yes' ? (step.node.yesLabel ?? 'Yes') : (step.node.noLabel ?? 'No')}
</span>
)}
</button>
<ChevronRight className="w-3 h-3 shrink-0" />
</React.Fragment>
);
})}
</div>
)}
{/* Active node */}
<div className="px-5 py-5">
{atLeaf ? (
/* Leaf result */
(() => {
const node = lastStep.node;
const rType = node.resultType ?? 'correct';
const s = RESULT_STYLES[rType];
return (
<div className={`rounded-xl border p-4 ${s.bg} ${s.border}`}>
<div className="flex gap-3">
{s.icon}
<div>
<p className={`font-semibold ${s.text} leading-snug`}>{node.result}</p>
{node.ruleRef && (
<p className={`mt-2 text-sm font-mono ${s.text} opacity-80 bg-white/60 rounded px-2 py-1 inline-block`}>
{node.ruleRef}
</p>
)}
</div>
</div>
</div>
);
})()
) : (
/* Decision question */
(() => {
const node = lastStep.node;
return (
<div>
<p className="font-semibold text-gray-800 text-base leading-snug mb-1">{node.question}</p>
{node.hint && <p className="text-sm text-gray-500 mb-4">{node.hint}</p>}
{!node.hint && <div className="mb-4" />}
<div className="flex flex-wrap gap-3">
<button
onClick={() => handleAnswer(node.id, 'yes')}
className="flex-1 min-w-[140px] px-4 py-3 rounded-xl border-2 border-green-300 bg-green-50 text-green-800 font-semibold text-sm hover:bg-green-100 transition-colors"
>
{node.yesLabel ?? 'Yes'}
</button>
<button
onClick={() => handleAnswer(node.id, 'no')}
className="flex-1 min-w-[140px] px-4 py-3 rounded-xl border-2 border-red-200 bg-red-50 text-red-700 font-semibold text-sm hover:bg-red-100 transition-colors"
>
{node.noLabel ?? 'No'}
</button>
</div>
</div>
);
})()
)}
</div>
{/* Footer */}
<div className="px-5 pb-4 flex items-center gap-3">
<button
onClick={resetScenario}
className="flex items-center gap-1.5 text-sm text-gray-500 hover:text-gray-700 transition-colors"
>
<RotateCcw className="w-3.5 h-3.5" />
Try again
</button>
{atLeaf && scenarios.length > 1 && activeScenario < scenarios.length - 1 && (
<button
onClick={() => switchScenario(activeScenario + 1)}
className={`ml-auto flex items-center gap-1.5 text-sm font-semibold text-${accentColor}-700 hover:text-${accentColor}-900 transition-colors`}
>
Next sentence <ChevronRight className="w-4 h-4" />
</button>
)}
</div>
</div>
);
}

View File

@ -0,0 +1,80 @@
import React, { useState } from 'react';
const DiscriminantWidget: React.FC = () => {
const [a, setA] = useState(1);
const [b, setB] = useState(-4);
const [c, setC] = useState(3); // Default x^2 - 4x + 3 (Roots 1, 3)
const discriminant = b*b - 4*a*c;
const rootsCount = discriminant > 0 ? 2 : discriminant === 0 ? 1 : 0;
// Viewport
const range = 10;
const size = 300;
const scale = size / (range * 2);
const center = size / 2;
const toPx = (v: number, isY = false) => isY ? center - v * scale : center + v * scale;
const generatePath = () => {
let dStr = "";
for (let x = -range; x <= range; x += 0.5) {
const y = a * x*x + b*x + c;
if (Math.abs(y) > range) continue;
const px = toPx(x);
const py = toPx(y, true);
dStr += dStr ? ` L ${px} ${py}` : `M ${px} ${py}`;
}
return dStr;
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col gap-6">
<div className="flex justify-between items-center bg-slate-50 p-4 rounded-lg border border-slate-200">
<div className="font-mono text-lg font-bold text-slate-800">
Δ = b² - 4ac = <span className={discriminant > 0 ? "text-green-600" : discriminant < 0 ? "text-rose-600" : "text-amber-600"}>{discriminant}</span>
</div>
<div className={`px-3 py-1 rounded text-sm font-bold uppercase text-white ${discriminant > 0 ? "bg-green-500" : discriminant < 0 ? "bg-rose-500" : "bg-amber-500"}`}>
{rootsCount} Real Solution{rootsCount !== 1 ? 's' : ''}
</div>
</div>
<div className="flex flex-col md:flex-row gap-8">
<div className="w-full md:w-1/3 space-y-4">
<div>
<label className="text-xs font-bold text-slate-500 uppercase">a = {a}</label>
<input type="range" min="-3" max="3" step="0.5" value={a} onChange={e => setA(parseFloat(e.target.value) || 0.1)} className="w-full h-1 bg-slate-200 rounded accent-slate-600"/>
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase">b = {b}</label>
<input type="range" min="-10" max="10" step="1" value={b} onChange={e => setB(parseFloat(e.target.value))} className="w-full h-1 bg-slate-200 rounded accent-slate-600"/>
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase">c = {c}</label>
<input type="range" min="-10" max="10" step="1" value={c} onChange={e => setC(parseFloat(e.target.value))} className="w-full h-1 bg-slate-200 rounded accent-slate-600"/>
</div>
<div className="text-xs text-slate-500 mt-4">
<p>If Δ &gt; 0: Crosses axis twice</p>
<p>If Δ = 0: Touches axis once (Vertex on axis)</p>
<p>If Δ &lt; 0: Never touches axis</p>
</div>
</div>
<div className="flex-1 flex justify-center">
<div className="relative w-[300px] h-[200px] bg-white border border-slate-200 rounded-xl overflow-hidden">
<svg width="100%" height="100%" viewBox="0 0 300 300" preserveAspectRatio="xMidYMid slice">
<line x1="0" y1={center} x2={size} y2={center} stroke="#cbd5e1" strokeWidth="2" />
<line x1={center} y1="0" x2={center} y2={size} stroke="#cbd5e1" strokeWidth="2" />
<path d={generatePath()} fill="none" stroke="#4f46e5" strokeWidth="3" />
</svg>
</div>
</div>
</div>
</div>
</div>
);
};
export default DiscriminantWidget;

View File

@ -0,0 +1,255 @@
import React, { useState } from "react";
import {
CheckCircle2,
XCircle,
RotateCcw,
ChevronRight,
MousePointerClick,
} from "lucide-react";
export interface EvidenceExercise {
question: string;
passage: string[]; // array of sentences rendered as a flowing paragraph
evidenceIndex: number; // 0-based index of the correct sentence
explanation: string;
}
interface EvidenceHunterWidgetProps {
exercises: EvidenceExercise[];
accentColor?: string;
}
// Tailwind needs complete class strings — map accent to concrete classes
const ACCENT: Record<
string,
{
tab: string;
header: string;
label: string;
hover: string;
selected: string;
btn: string;
next: string;
}
> = {
teal: {
tab: "border-b-2 border-teal-600 text-teal-700",
header: "bg-teal-50",
label: "text-teal-500",
hover: "hover:bg-teal-50 hover:border-teal-400",
selected: "bg-teal-100 border-teal-500",
btn: "bg-teal-600 hover:bg-teal-700",
next: "text-teal-700 hover:text-teal-900",
},
fuchsia: {
tab: "border-b-2 border-fuchsia-600 text-fuchsia-700",
header: "bg-fuchsia-50",
label: "text-fuchsia-500",
hover: "hover:bg-fuchsia-50 hover:border-fuchsia-400",
selected: "bg-fuchsia-100 border-fuchsia-500",
btn: "bg-fuchsia-600 hover:bg-fuchsia-700",
next: "text-fuchsia-700 hover:text-fuchsia-900",
},
purple: {
tab: "border-b-2 border-purple-600 text-purple-700",
header: "bg-purple-50",
label: "text-purple-500",
hover: "hover:bg-purple-50 hover:border-purple-400",
selected: "bg-purple-100 border-purple-500",
btn: "bg-purple-600 hover:bg-purple-700",
next: "text-purple-700 hover:text-purple-900",
},
amber: {
tab: "border-b-2 border-amber-600 text-amber-700",
header: "bg-amber-50",
label: "text-amber-500",
hover: "hover:bg-amber-50 hover:border-amber-400",
selected: "bg-amber-100 border-amber-500",
btn: "bg-amber-600 hover:bg-amber-700",
next: "text-amber-700 hover:text-amber-900",
},
};
export default function EvidenceHunterWidget({
exercises,
accentColor = "teal",
}: EvidenceHunterWidgetProps) {
const [activeEx, setActiveEx] = useState(0);
const [selected, setSelected] = useState<number | null>(null);
const [submitted, setSubmitted] = useState(false);
const exercise = exercises[activeEx];
const isCorrect = submitted && selected === exercise.evidenceIndex;
const c = ACCENT[accentColor] ?? ACCENT.teal;
const reset = () => {
setSelected(null);
setSubmitted(false);
};
const switchEx = (i: number) => {
setActiveEx(i);
setSelected(null);
setSubmitted(false);
};
return (
<div className="rounded-2xl border border-gray-200 bg-white overflow-hidden shadow-sm">
{/* Tab strip */}
{exercises.length > 1 && (
<div className="flex border-b border-gray-200 bg-gray-50 overflow-x-auto">
{exercises.map((_, i) => (
<button
key={i}
onClick={() => switchEx(i)}
className={`px-4 py-2.5 text-sm font-medium whitespace-nowrap transition-colors bg-white ${
i === activeEx ? c.tab : "text-gray-500 hover:text-gray-700"
}`}
>
Passage {i + 1}
</button>
))}
</div>
)}
{/* Question */}
<div className={`px-5 py-4 border-b border-gray-200 ${c.header}`}>
<p
className={`text-xs font-bold uppercase tracking-wider mb-1.5 ${c.label}`}
>
Question
</p>
<p className="text-gray-800 font-semibold leading-snug text-base">
{exercise.question}
</p>
</div>
{/* Passage — flowing text with inline clickable sentences */}
<div className="px-5 pt-5 pb-3">
<div className="flex items-center gap-2 mb-3">
<p className="text-xs font-semibold text-gray-500 uppercase tracking-wider">
Passage
</p>
{!submitted && (
<span className="flex items-center gap-1 text-xs text-gray-400 italic">
<MousePointerClick className="w-3 h-3" /> click the sentence that
answers the question
</span>
)}
</div>
{/* Render as a flowing paragraph with clickable sentence spans */}
<div className="text-sm text-gray-700 leading-8 bg-gray-50 rounded-xl border border-gray-200 px-5 py-4 select-none">
{exercise.passage.map((sentence, i) => {
// Determine highlight class for this sentence
let spanCls = `inline cursor-pointer rounded px-0.5 py-0.5 border border-transparent transition-all ${c.hover}`;
if (submitted) {
if (i === exercise.evidenceIndex) {
spanCls =
"inline rounded px-0.5 py-0.5 border bg-green-100 border-green-400 text-green-800 font-medium cursor-default";
} else if (i === selected) {
spanCls =
"inline rounded px-0.5 py-0.5 border bg-red-100 border-red-300 text-red-600 cursor-default line-through";
} else {
spanCls =
"inline rounded px-0.5 py-0.5 border border-transparent text-gray-400 cursor-default";
}
} else if (selected === i) {
spanCls = `inline rounded px-0.5 py-0.5 border cursor-pointer ${c.selected} font-medium`;
}
return (
<React.Fragment key={i}>
<span
onClick={() => {
if (!submitted) setSelected(i);
}}
className={spanCls}
title={
submitted ? undefined : `Click to select sentence ${i + 1}`
}
>
{sentence}
</span>
{i < exercise.passage.length - 1 ? " " : ""}
</React.Fragment>
);
})}
</div>
{/* Selection indicator */}
{!submitted && selected !== null && (
<p className="mt-2 text-xs text-gray-500 italic">
Selected:{" "}
<span className="font-semibold text-gray-700">
"{exercise.passage[selected].slice(0, 60)}
{exercise.passage[selected].length > 60 ? "" : ""}"
</span>
</p>
)}
{!submitted && selected === null && (
<p className="mt-2 text-xs text-gray-400 italic">
No sentence selected yet.
</p>
)}
</div>
{/* Submit / result */}
<div className="px-5 pb-5">
{!submitted ? (
<button
disabled={selected === null}
onClick={() => setSubmitted(true)}
className={`mt-2 px-5 py-2.5 rounded-full text-sm font-bold text-white transition-colors ${
selected !== null
? c.btn
: "bg-gray-200 text-gray-400 cursor-not-allowed"
}`}
>
Check my answer
</button>
) : (
<div
className={`mt-3 rounded-xl border p-4 ${isCorrect ? "bg-green-50 border-green-300" : "bg-amber-50 border-amber-300"}`}
>
<div className="flex gap-2 mb-2">
{isCorrect ? (
<CheckCircle2 className="w-5 h-5 text-green-600 shrink-0 mt-0.5" />
) : (
<XCircle className="w-5 h-5 text-amber-600 shrink-0 mt-0.5" />
)}
<p
className={`font-semibold text-sm ${isCorrect ? "text-green-800" : "text-amber-800"}`}
>
{isCorrect
? "Correct — that's the key sentence."
: `Not quite. The highlighted sentence above is the correct one.`}
</p>
</div>
<p className="text-sm text-gray-700 leading-relaxed">
{exercise.explanation}
</p>
</div>
)}
<div className="flex items-center gap-3 mt-3">
{submitted && (
<button
onClick={reset}
className="flex items-center gap-1.5 text-sm text-gray-500 hover:text-gray-700 transition-colors"
>
<RotateCcw className="w-3.5 h-3.5" /> Try again
</button>
)}
{submitted && activeEx < exercises.length - 1 && (
<button
onClick={() => switchEx(activeEx + 1)}
className={`ml-auto flex items-center gap-1.5 text-sm font-semibold transition-colors ${c.next}`}
>
Next passage <ChevronRight className="w-4 h-4" />
</button>
)}
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,88 @@
import React, { useState } from 'react';
const ExponentialExplorer: React.FC = () => {
const [a, setA] = useState(2); // Initial Value
const [b, setB] = useState(1.5); // Growth Factor
const [k, setK] = useState(0); // Horizontal Asymptote shift
const width = 300;
const height = 300;
const range = 5; // x range -5 to 5
// Mapping
const toPx = (v: number, isY = false) => {
const scale = width / (range * 2);
const center = width / 2;
return isY ? center - v * scale : center + v * scale;
};
const generatePath = () => {
let d = "";
for (let x = -range; x <= range; x += 0.1) {
const y = a * Math.pow(b, x) + k;
if (y > range * 2 || y < -range * 2) continue; // Clip
const px = toPx(x);
const py = toPx(y, true);
d += d ? ` L ${px} ${py}` : `M ${px} ${py}`;
}
return d;
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8">
<div className="w-full md:w-1/3 space-y-6">
<div className="p-4 bg-violet-50 rounded-xl border border-violet-100 text-center">
<div className="text-xs font-bold text-violet-400 uppercase mb-1">Standard Form</div>
<div className="text-xl font-mono font-bold text-violet-900">
y = <span className="text-indigo-600">{a}</span> · <span className="text-emerald-600">{b}</span><sup>x</sup> {k >= 0 ? '+' : ''} <span className="text-rose-600">{k}</span>
</div>
</div>
<div className="space-y-4">
<div>
<label className="text-xs font-bold text-indigo-600 uppercase flex justify-between">
Initial Value (a) <span>{a}</span>
</label>
<input type="range" min="0.5" max="5" step="0.5" value={a} onChange={e => setA(parseFloat(e.target.value))} className="w-full h-2 bg-indigo-100 rounded-lg appearance-none cursor-pointer accent-indigo-600"/>
</div>
<div>
<label className="text-xs font-bold text-emerald-600 uppercase flex justify-between">
Growth Factor (b) <span>{b}</span>
</label>
<input type="range" min="0.1" max="3" step="0.1" value={b} onChange={e => setB(parseFloat(e.target.value))} className="w-full h-2 bg-emerald-100 rounded-lg appearance-none cursor-pointer accent-emerald-600"/>
<p className="text-xs text-slate-400 mt-1">{b > 1 ? "Growth (b > 1)" : "Decay (0 < b < 1)"}</p>
</div>
<div>
<label className="text-xs font-bold text-rose-600 uppercase flex justify-between">
Vertical Shift (k) <span>{k}</span>
</label>
<input type="range" min="-3" max="3" step="1" value={k} onChange={e => setK(parseFloat(e.target.value))} className="w-full h-2 bg-rose-100 rounded-lg appearance-none cursor-pointer accent-rose-600"/>
</div>
</div>
</div>
<div className="flex-1 flex justify-center">
<div className="relative w-[300px] h-[300px] bg-white border border-slate-200 rounded-xl overflow-hidden">
<svg width="100%" height="100%" viewBox="0 0 300 300">
<line x1="0" y1="150" x2="300" y2="150" stroke="#cbd5e1" strokeWidth="2" />
<line x1="150" y1="0" x2="150" y2="300" stroke="#cbd5e1" strokeWidth="2" />
{/* Asymptote */}
<line x1="0" y1={toPx(k, true)} x2="300" y2={toPx(k, true)} stroke="#e11d48" strokeWidth="1" strokeDasharray="4,4" />
<text x="10" y={toPx(k, true) - 5} className="text-xs font-bold fill-rose-500">y = {k}</text>
{/* Function */}
<path d={generatePath()} fill="none" stroke="#8b5cf6" strokeWidth="3" />
{/* Intercept */}
<circle cx={toPx(0)} cy={toPx(a+k, true)} r="4" fill="#4f46e5" stroke="white" strokeWidth="2" />
</svg>
</div>
</div>
</div>
</div>
);
};
export default ExponentialExplorer;

View File

@ -0,0 +1,116 @@
import React, { useState } from 'react';
const FactoringWidget: React.FC = () => {
// ax^2 + bx + c
const [a, setA] = useState(1);
const [b, setB] = useState(5);
const [c, setC] = useState(6);
const product = a * c;
const sum = b;
// We won't solve it for them immediately, let them guess or think
// But we will show if it's factorable over integers
// Simple check for nice numbers
const getFactors = () => {
// Find two numbers p, q such that p*q = product and p+q = sum
// Brute force range reasonable for typical SAT (up to +/- 100)
for (let i = -100; i <= 100; i++) {
if (i === 0) continue;
const q = product / i;
if (Math.abs(q - Math.round(q)) < 0.001) { // is integer
if (i + q === sum) return [i, q].sort((x,y) => x-y);
}
}
return null;
};
const solution = getFactors();
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8 items-center">
{/* Input Side */}
<div className="w-full md:w-1/2 space-y-4">
<h4 className="font-bold text-violet-900 mb-2">Polynomial: <span className="font-mono text-lg">{a === 1 ? '' : a}x² {b >= 0 ? '+' : ''}{b}x {c >= 0 ? '+' : ''}{c}</span></h4>
<div className="grid grid-cols-3 gap-2">
<div>
<label className="text-xs font-bold text-slate-400">a</label>
<input type="number" value={a} onChange={e => setA(parseInt(e.target.value) || 0)} className="w-full p-2 border rounded font-mono font-bold text-center" />
</div>
<div>
<label className="text-xs font-bold text-slate-400">b (Sum)</label>
<input type="number" value={b} onChange={e => setB(parseInt(e.target.value) || 0)} className="w-full p-2 border rounded font-mono font-bold text-center" />
</div>
<div>
<label className="text-xs font-bold text-slate-400">c</label>
<input type="number" value={c} onChange={e => setC(parseInt(e.target.value) || 0)} className="w-full p-2 border rounded font-mono font-bold text-center" />
</div>
</div>
<div className="p-4 bg-slate-50 rounded-lg text-sm text-slate-600">
<p><strong>AC Method (Diamond):</strong></p>
<p>Find two numbers that multiply to <strong>a·c</strong> and add to <strong>b</strong>.</p>
<p className="mt-2 font-mono text-center">
Product (ac) = {a} × {c} = <strong>{product}</strong> <br/>
Sum (b) = <strong>{sum}</strong>
</p>
</div>
</div>
{/* Visual Side */}
<div className="flex-1 flex flex-col items-center justify-center">
<div className="relative w-48 h-48">
{/* X Shape */}
<div className="absolute top-0 left-0 w-full h-full">
<svg width="100%" height="100%" viewBox="0 0 200 200">
<line x1="20" y1="20" x2="180" y2="180" stroke="#cbd5e1" strokeWidth="4" />
<line x1="180" y1="20" x2="20" y2="180" stroke="#cbd5e1" strokeWidth="4" />
</svg>
</div>
{/* Top (Product) */}
<div className="absolute top-0 left-1/2 -translate-x-1/2 -translate-y-4 bg-violet-100 px-3 py-1 rounded border border-violet-300 text-violet-800 font-bold shadow-sm">
{product}
</div>
{/* Bottom (Sum) */}
<div className="absolute bottom-0 left-1/2 -translate-x-1/2 translate-y-4 bg-indigo-100 px-3 py-1 rounded border border-indigo-300 text-indigo-800 font-bold shadow-sm">
{sum}
</div>
{/* Left (Factor 1) */}
<div className="absolute left-0 top-1/2 -translate-x-6 -translate-y-1/2 bg-white px-3 py-2 rounded border-2 border-emerald-400 text-emerald-700 font-bold shadow-md min-w-[3rem] text-center">
{solution ? solution[0] : "?"}
</div>
{/* Right (Factor 2) */}
<div className="absolute right-0 top-1/2 translate-x-6 -translate-y-1/2 bg-white px-3 py-2 rounded border-2 border-emerald-400 text-emerald-700 font-bold shadow-md min-w-[3rem] text-center">
{solution ? solution[1] : "?"}
</div>
</div>
<div className="mt-8 text-center">
{solution ? (
<div className="text-emerald-700 font-bold bg-emerald-50 px-4 py-2 rounded-lg border border-emerald-200">
Factors Found: {solution[0]} and {solution[1]}
{a === 1 && (
<div className="text-sm mt-1 font-mono text-slate-600">
(x {solution[0] >= 0 ? '+' : ''}{solution[0]})(x {solution[1] >= 0 ? '+' : ''}{solution[1]})
</div>
)}
</div>
) : (
<div className="text-rose-600 font-bold text-sm bg-rose-50 px-4 py-2 rounded-lg border border-rose-200">
No integer factors found. (Prime)
</div>
)}
</div>
</div>
</div>
</div>
);
};
export default FactoringWidget;

View File

@ -0,0 +1,114 @@
import React, { useState } from 'react';
const FrequencyMeanWidget: React.FC = () => {
// Data: Value -> Frequency
const [counts, setCounts] = useState({ 0: 3, 1: 5, 2: 6, 3: 4, 4: 2 });
const handleChange = (val: number, delta: number) => {
setCounts(prev => ({
...prev,
[val]: Math.max(0, (prev[val as keyof typeof prev] || 0) + delta)
}));
};
const values = [0, 1, 2, 3, 4];
const totalStudents = values.reduce((sum, v) => sum + counts[v as keyof typeof counts], 0);
const totalBooks = values.reduce((sum, v) => sum + v * counts[v as keyof typeof counts], 0);
const mean = totalStudents > 0 ? (totalBooks / totalStudents).toFixed(2) : '0';
// Calculate Median position
let cumulative = 0;
let medianVal = 0;
const mid = (totalStudents + 1) / 2;
if (totalStudents > 0) {
for (const v of values) {
cumulative += counts[v as keyof typeof counts];
if (cumulative >= mid) {
medianVal = v;
break;
}
}
}
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{/* Table Control */}
<div>
<h4 className="font-bold text-slate-700 mb-4 flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-amber-500"></span>
Edit Frequencies
</h4>
<div className="overflow-hidden rounded-lg border border-slate-200">
<table className="w-full text-sm text-center">
<thead className="bg-slate-50 text-slate-500 font-bold uppercase">
<tr>
<th className="p-3 border-b border-r border-slate-200">Books Read</th>
<th className="p-3 border-b border-slate-200">Students (Freq)</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-100">
{values.map(v => (
<tr key={v} className="group hover:bg-amber-50/50 transition-colors">
<td className="p-3 border-r border-slate-100 font-mono font-bold text-slate-700">{v}</td>
<td className="p-2 flex justify-center items-center gap-3">
<button
onClick={() => handleChange(v, -1)}
className="w-6 h-6 rounded bg-slate-100 hover:bg-slate-200 text-slate-600 font-bold flex items-center justify-center transition-colors"
>-</button>
<span className="w-4 font-mono font-bold text-slate-800">{counts[v as keyof typeof counts]}</span>
<button
onClick={() => handleChange(v, 1)}
className="w-6 h-6 rounded bg-amber-100 hover:bg-amber-200 text-amber-700 font-bold flex items-center justify-center transition-colors"
>+</button>
</td>
</tr>
))}
<tr className="bg-slate-50 font-bold text-slate-800">
<td className="p-3 border-r border-slate-200">TOTAL</td>
<td className="p-3">{totalStudents}</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* Visualization & Stats */}
<div className="flex flex-col justify-between">
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200 mb-6">
<h4 className="text-xs font-bold text-slate-400 uppercase mb-3">Dot Plot Preview</h4>
<div className="flex justify-between items-end h-32 px-2 pb-2 border-b border-slate-300">
{values.map(v => (
<div key={v} className="flex flex-col-reverse items-center gap-1 w-8">
{Array.from({length: counts[v as keyof typeof counts]}).map((_, i) => (
<div key={i} className="w-3 h-3 rounded-full bg-amber-500 shadow-sm"></div>
))}
</div>
))}
</div>
<div className="flex justify-between px-2 pt-2 text-xs font-mono font-bold text-slate-500">
{values.map(v => <span key={v} className="w-8 text-center">{v}</span>)}
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="p-4 bg-indigo-50 border border-indigo-100 rounded-lg">
<p className="text-xs font-bold text-indigo-400 uppercase">Weighted Mean</p>
<p className="text-2xl font-bold text-indigo-700">{mean}</p>
<p className="text-[10px] text-indigo-400 mt-1">Total Books ({totalBooks}) / Students ({totalStudents})</p>
</div>
<div className="p-4 bg-emerald-50 border border-emerald-100 rounded-lg">
<p className="text-xs font-bold text-emerald-400 uppercase">Median</p>
<p className="text-2xl font-bold text-emerald-700">{medianVal}</p>
<p className="text-[10px] text-emerald-400 mt-1">Middle Position (~{mid.toFixed(1)})</p>
</div>
</div>
</div>
</div>
</div>
);
};
export default FrequencyMeanWidget;

View File

@ -0,0 +1,84 @@
import React, { useState } from 'react';
const GrowthComparisonWidget: React.FC = () => {
const [linearRate, setLinearRate] = useState(10); // +10 per step
const [expRate, setExpRate] = useState(10); // +10% per step
const start = 100;
const steps = 10;
// Generate Data
const data = Array.from({ length: steps + 1 }, (_, i) => {
return {
x: i,
lin: start + linearRate * i,
exp: start * Math.pow(1 + expRate/100, i)
};
});
const maxY = Math.max(data[steps].lin, data[steps].exp);
// Scales
const width = 100;
const height = 60;
const getX = (i: number) => (i / steps) * width;
const getY = (val: number) => height - (val / maxY) * height; // Inverted Y
const linPath = `M ${data.map(d => `${getX(d.x)},${getY(d.lin)}`).join(' L ')}`;
const expPath = `M ${data.map(d => `${getX(d.x)},${getY(d.exp)}`).join(' L ')}`;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="grid grid-cols-2 gap-8 mb-6">
<div>
<label className="text-xs font-bold text-indigo-600 uppercase">Linear Rate (+)</label>
<input
type="range" min="5" max="50" value={linearRate}
onChange={e => setLinearRate(Number(e.target.value))}
className="w-full h-2 bg-indigo-100 rounded-lg appearance-none cursor-pointer accent-indigo-600 mt-2"
/>
<div className="text-right font-mono font-bold text-indigo-700">+{linearRate} / step</div>
</div>
<div>
<label className="text-xs font-bold text-rose-600 uppercase">Exponential Rate (%)</label>
<input
type="range" min="2" max="30" value={expRate}
onChange={e => setExpRate(Number(e.target.value))}
className="w-full h-2 bg-rose-100 rounded-lg appearance-none cursor-pointer accent-rose-600 mt-2"
/>
<div className="text-right font-mono font-bold text-rose-700">+{expRate}% / step</div>
</div>
</div>
<div className="relative h-64 w-full bg-slate-50 rounded-lg border border-slate-200 mb-6 overflow-hidden">
<svg viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="none" className="w-full h-full p-4 overflow-visible">
{/* Grid */}
<line x1="0" y1={height} x2={width} y2={height} stroke="#cbd5e1" strokeWidth="0.5" />
<line x1="0" y1="0" x2="0" y2={height} stroke="#cbd5e1" strokeWidth="0.5" />
{/* Paths */}
<path d={linPath} fill="none" stroke="#4f46e5" strokeWidth="1" />
<path d={expPath} fill="none" stroke="#e11d48" strokeWidth="1" />
{/* Points */}
{data.map((d, i) => (
<g key={i}>
<circle cx={getX(d.x)} cy={getY(d.lin)} r="1" fill="#4f46e5" />
<circle cx={getX(d.x)} cy={getY(d.exp)} r="1" fill="#e11d48" />
</g>
))}
</svg>
{/* Labels */}
<div className="absolute top-2 right-2 text-xs font-bold bg-white/80 p-2 rounded shadow-sm">
<div className="text-indigo-600">Linear Final: {Math.round(data[steps].lin)}</div>
<div className="text-rose-600">Exp Final: {Math.round(data[steps].exp)}</div>
</div>
</div>
<p className="text-sm text-slate-500">
Exponential growth eventually overtakes Linear growth, even if the linear rate seems larger at first!
</p>
</div>
);
};
export default GrowthComparisonWidget;

View File

@ -0,0 +1,86 @@
import React, { useState } from 'react';
const HistogramBuilderWidget: React.FC = () => {
const [mode, setMode] = useState<'count' | 'percent'>('count');
// Data: [60, 70), [70, 80), [80, 90), [90, 100)
const data = [
{ bin: '60-70', count: 4, label: '60s' },
{ bin: '70-80', count: 9, label: '70s' },
{ bin: '80-90', count: 6, label: '80s' },
{ bin: '90-100', count: 1, label: '90s' },
];
const total = data.reduce((acc, curr) => acc + curr.count, 0); // 20
const maxCount = Math.max(...data.map(d => d.count));
const maxPercent = maxCount / total; // 0.45
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex justify-between items-center mb-6">
<h3 className="font-bold text-slate-700">Test Scores Distribution</h3>
<div className="flex bg-slate-100 p-1 rounded-lg">
<button
onClick={() => setMode('count')}
className={`px-4 py-1.5 text-sm font-bold rounded-md transition-all ${mode === 'count' ? 'bg-white shadow-sm text-indigo-600' : 'text-slate-500 hover:text-slate-700'}`}
>
Frequency (Count)
</button>
<button
onClick={() => setMode('percent')}
className={`px-4 py-1.5 text-sm font-bold rounded-md transition-all ${mode === 'percent' ? 'bg-white shadow-sm text-rose-600' : 'text-slate-500 hover:text-slate-700'}`}
>
Relative Freq (%)
</button>
</div>
</div>
<div className="relative h-64 border-b-2 border-slate-200 flex items-end px-8 gap-1">
{/* Y Axis Labels */}
<div className="absolute left-0 top-0 bottom-0 flex flex-col justify-between text-xs font-mono text-slate-400 py-2">
<span>{mode === 'count' ? maxCount + 1 : ((maxPercent + 0.05)*100).toFixed(0) + '%'}</span>
<span>{mode === 'count' ? Math.round((maxCount+1)/2) : (((maxPercent + 0.05)/2)*100).toFixed(0) + '%'}</span>
<span>0</span>
</div>
{data.map((d, i) => {
const heightRatio = d.count / maxCount; // Normalize to max height of graph area roughly
// Actually map 0 to maxScale
const maxScale = mode === 'count' ? maxCount + 1 : (maxPercent + 0.05);
const val = mode === 'count' ? d.count : d.count / total;
const hPercent = (val / maxScale) * 100;
return (
<div key={i} className="flex-1 flex flex-col justify-end group relative h-full">
{/* Tooltip */}
<div className="opacity-0 group-hover:opacity-100 absolute -top-10 left-1/2 -translate-x-1/2 bg-slate-800 text-white text-xs py-1 px-2 rounded pointer-events-none transition-opacity z-10 whitespace-nowrap">
{d.bin}: {mode === 'count' ? d.count : `${(d.count/total*100).toFixed(0)}%`}
</div>
{/* Bar */}
<div
className={`w-full transition-all duration-500 rounded-t ${mode === 'count' ? 'bg-indigo-500 group-hover:bg-indigo-600' : 'bg-rose-500 group-hover:bg-rose-600'}`}
style={{ height: `${hPercent}%` }}
></div>
{/* Bin Label */}
<div className="absolute -bottom-6 w-full text-center text-xs font-bold text-slate-500">
{d.label}
</div>
</div>
);
})}
</div>
<div className="mt-8 p-4 bg-slate-50 rounded-xl border border-slate-200">
<p className="text-sm text-slate-600">
<strong>Key Takeaway:</strong> Notice that the <span className="font-bold text-slate-800">shape</span> of the distribution stays exactly the same.
Only the <span className="font-bold text-slate-800">Y-axis scale</span> changes.
</p>
</div>
</div>
);
};
export default HistogramBuilderWidget;

View File

@ -0,0 +1,173 @@
import React, { useState, useRef } from 'react';
const InequalityRegionWidget: React.FC = () => {
// State for Inequalities: y > or < mx + b
// isGreater: true for >=, false for <=
const [ineq1, setIneq1] = useState({ m: 1, b: 1, isGreater: true });
const [ineq2, setIneq2] = useState({ m: -0.5, b: -2, isGreater: false });
const [testPoint, setTestPoint] = useState({ x: 0, y: 0 });
const isDragging = useRef(false);
const svgRef = useRef<SVGSVGElement>(null);
// Viewport
const range = 10;
const size = 300;
const scale = size / (range * 2);
const center = size / 2;
// Helpers
const toPx = (val: number, isY = false) => {
return isY ? center - val * scale : center + val * scale;
};
const fromPx = (px: number, isY = false) => {
return isY ? (center - px) / scale : (px - center) / scale;
};
// Generate polygon points for shading
const getRegionPoints = (m: number, b: number, isGreater: boolean) => {
const xMin = -range;
const xMax = range;
const yAtMin = m * xMin + b;
const yAtMax = m * xMax + b;
// y limit is the top (range) or bottom (-range) of the graph
const limitY = isGreater ? range : -range;
const p1 = { x: xMin, y: yAtMin };
const p2 = { x: xMax, y: yAtMax };
const p3 = { x: xMax, y: limitY };
const p4 = { x: xMin, y: limitY };
return `${toPx(p1.x)},${toPx(p1.y, true)} ${toPx(p2.x)},${toPx(p2.y, true)} ${toPx(p3.x)},${toPx(p3.y, true)} ${toPx(p4.x)},${toPx(p4.y, true)}`;
};
const getLinePath = (m: number, b: number) => {
const x1 = -range;
const y1 = m * x1 + b;
const x2 = range;
const y2 = m * x2 + b;
return `M ${toPx(x1)} ${toPx(y1, true)} L ${toPx(x2)} ${toPx(y2, true)}`;
};
// Interaction
const handleInteraction = (e: React.MouseEvent) => {
if (!svgRef.current) return;
const rect = svgRef.current.getBoundingClientRect();
const x = fromPx(e.clientX - rect.left);
const y = fromPx(e.clientY - rect.top, true);
// Clamp
const cx = Math.max(-range, Math.min(range, x));
const cy = Math.max(-range, Math.min(range, y));
setTestPoint({ x: cx, y: cy });
};
// Logic Check
const check1 = ineq1.isGreater ? testPoint.y >= ineq1.m * testPoint.x + ineq1.b : testPoint.y <= ineq1.m * testPoint.x + ineq1.b;
const check2 = ineq2.isGreater ? testPoint.y >= ineq2.m * testPoint.x + ineq2.b : testPoint.y <= ineq2.m * testPoint.x + ineq2.b;
const isSolution = check1 && check2;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8">
{/* Controls */}
<div className="w-full md:w-1/3 space-y-6">
{/* Inequality 1 */}
<div className={`p-4 rounded-lg border ${check1 ? 'bg-indigo-50 border-indigo-200' : 'bg-slate-50 border-slate-200'}`}>
<div className="flex justify-between items-center mb-2">
<span className="font-bold text-indigo-800 text-sm">Region 1 (Blue)</span>
<button
onClick={() => setIneq1(p => ({...p, isGreater: !p.isGreater}))}
className="text-xs bg-white border border-indigo-200 px-2 py-1 rounded font-bold text-indigo-600"
>
{ineq1.isGreater ? 'y ≥ ...' : 'y ≤ ...'}
</button>
</div>
<div className="space-y-3">
<div>
<div className="flex justify-between text-xs text-slate-500"><span>Slope</span><span>{ineq1.m}</span></div>
<input type="range" min="-4" max="4" step="0.5" value={ineq1.m} onChange={e => setIneq1({...ineq1, m: parseFloat(e.target.value)})} className="w-full h-1 bg-indigo-200 rounded accent-indigo-600"/>
</div>
<div>
<div className="flex justify-between text-xs text-slate-500"><span>Y-Int</span><span>{ineq1.b}</span></div>
<input type="range" min="-8" max="8" step="1" value={ineq1.b} onChange={e => setIneq1({...ineq1, b: parseFloat(e.target.value)})} className="w-full h-1 bg-indigo-200 rounded accent-indigo-600"/>
</div>
</div>
</div>
{/* Inequality 2 */}
<div className={`p-4 rounded-lg border ${check2 ? 'bg-rose-50 border-rose-200' : 'bg-slate-50 border-slate-200'}`}>
<div className="flex justify-between items-center mb-2">
<span className="font-bold text-rose-800 text-sm">Region 2 (Red)</span>
<button
onClick={() => setIneq2(p => ({...p, isGreater: !p.isGreater}))}
className="text-xs bg-white border border-rose-200 px-2 py-1 rounded font-bold text-rose-600"
>
{ineq2.isGreater ? 'y ≥ ...' : 'y ≤ ...'}
</button>
</div>
<div className="space-y-3">
<div>
<div className="flex justify-between text-xs text-slate-500"><span>Slope</span><span>{ineq2.m}</span></div>
<input type="range" min="-4" max="4" step="0.5" value={ineq2.m} onChange={e => setIneq2({...ineq2, m: parseFloat(e.target.value)})} className="w-full h-1 bg-rose-200 rounded accent-rose-600"/>
</div>
<div>
<div className="flex justify-between text-xs text-slate-500"><span>Y-Int</span><span>{ineq2.b}</span></div>
<input type="range" min="-8" max="8" step="1" value={ineq2.b} onChange={e => setIneq2({...ineq2, b: parseFloat(e.target.value)})} className="w-full h-1 bg-rose-200 rounded accent-rose-600"/>
</div>
</div>
</div>
<div className={`p-3 rounded-lg text-center font-bold text-sm border-2 transition-colors ${isSolution ? 'bg-emerald-100 border-emerald-400 text-emerald-800' : 'bg-slate-100 border-slate-300 text-slate-500'}`}>
Test Point: ({testPoint.x.toFixed(1)}, {testPoint.y.toFixed(1)}) <br/>
{isSolution ? "SOLUTION FOUND" : "NOT A SOLUTION"}
</div>
</div>
{/* Graph */}
<div className="flex-1 flex justify-center">
<div className="relative w-[300px] h-[300px] bg-white border border-slate-200 rounded-xl overflow-hidden cursor-crosshair">
<svg
ref={svgRef}
width="300" height="300" viewBox="0 0 300 300"
onMouseDown={(e) => { isDragging.current = true; handleInteraction(e); }}
onMouseMove={(e) => { if(isDragging.current) handleInteraction(e); }}
onMouseUp={() => isDragging.current = false}
onMouseLeave={() => isDragging.current = false}
>
<defs>
<pattern id="grid-ineq" width="15" height="15" patternUnits="userSpaceOnUse">
<path d="M 15 0 L 0 0 0 15" fill="none" stroke="#f8fafc" strokeWidth="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid-ineq)" />
{/* Axes */}
<line x1="0" y1={center} x2={size} y2={center} stroke="#cbd5e1" strokeWidth="2" />
<line x1={center} y1="0" x2={center} y2={size} stroke="#cbd5e1" strokeWidth="2" />
{/* Region 1 */}
<polygon points={getRegionPoints(ineq1.m, ineq1.b, ineq1.isGreater)} fill="rgba(99, 102, 241, 0.2)" />
<path d={getLinePath(ineq1.m, ineq1.b)} stroke="#4f46e5" strokeWidth="2" />
{/* Region 2 */}
<polygon points={getRegionPoints(ineq2.m, ineq2.b, ineq2.isGreater)} fill="rgba(225, 29, 72, 0.2)" />
<path d={getLinePath(ineq2.m, ineq2.b)} stroke="#e11d48" strokeWidth="2" />
{/* Test Point */}
<circle
cx={toPx(testPoint.x)} cy={toPx(testPoint.y, true)} r="6"
fill={isSolution ? "#10b981" : "#64748b"} stroke="white" strokeWidth="2" className="shadow-sm"
/>
</svg>
</div>
</div>
</div>
</div>
);
};
export default InequalityRegionWidget;

View File

@ -0,0 +1,232 @@
import React, { useState, useRef } from "react";
const InteractiveSectorWidget: React.FC = () => {
const [angle, setAngle] = useState(60); // degrees
const [radius, setRadius] = useState(120); // pixels
const isDragging = useRef<"angle" | "radius" | null>(null);
const svgRef = useRef<SVGSVGElement>(null);
const cx = 200;
const cy = 200;
const maxRadius = 160;
// Calculate Handle Position
const rad = (angle * Math.PI) / 180;
const hx = cx + radius * Math.cos(-rad); // SVG Y is down, so -rad for standard math "up" rotation behavior if we want counter-clockwise from East
const hy = cy + radius * Math.sin(-rad);
// For the arc path
// Start point is (cx + r, cy) [0 degrees]
// End point is (hx, hy)
const largeArc = angle > 180 ? 1 : 0;
// Sweep flag 0 because we are using -rad (counter clockwise visual in SVG)
const pathData = `
M ${cx} ${cy}
L ${cx + radius} ${cy}
A ${radius} ${radius} 0 ${largeArc} 0 ${hx} ${hy}
Z
`;
// Interaction
const handleInteraction = (e: React.MouseEvent) => {
if (!svgRef.current || !isDragging.current) return;
const rect = svgRef.current.getBoundingClientRect();
const mx = e.clientX - rect.left;
const my = e.clientY - rect.top;
const dx = mx - cx;
const dy = my - cy;
if (isDragging.current === "angle") {
let deg = Math.atan2(-dy, dx) * (180 / Math.PI); // -dy to correct for SVG coords
if (deg < 0) deg += 360;
setAngle(Math.round(deg));
} else if (isDragging.current === "radius") {
const dist = Math.sqrt(dx * dx + dy * dy);
setRadius(Math.max(50, Math.min(maxRadius, dist)));
}
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200 flex flex-col md:flex-row items-center gap-8">
<div className="relative select-none">
<svg
ref={svgRef}
width="400"
height="400"
onMouseMove={handleInteraction}
onMouseUp={() => (isDragging.current = null)}
onMouseLeave={() => (isDragging.current = null)}
className="cursor-crosshair"
>
{/* Full Circle Ghost */}
<circle
cx={cx}
cy={cy}
r={radius}
stroke="#e2e8f0"
strokeWidth="1"
fill="none"
strokeDasharray="4,4"
/>
{/* Sector */}
<path
d={pathData}
fill="rgba(249, 115, 22, 0.2)"
stroke="#f97316"
strokeWidth="2"
/>
{/* Radius Handle Line (Baseline) */}
<line
x1={cx}
y1={cy}
x2={cx + radius}
y2={cy}
stroke="#cbd5e1"
strokeWidth="2"
/>
{/* Radius Drag Handle (on baseline) */}
<circle
cx={cx + radius}
cy={cy}
r={8}
fill="#94a3b8"
stroke="white"
strokeWidth="2"
className="cursor-ew-resize hover:fill-slate-600 shadow-sm"
onMouseDown={() => (isDragging.current = "radius")}
/>
{/* Angle Drag Handle (on arc) */}
<circle
cx={hx}
cy={hy}
r={10}
fill="#f97316"
stroke="white"
strokeWidth="2"
className="cursor-pointer hover:scale-110 transition-transform shadow-md"
onMouseDown={() => (isDragging.current = "angle")}
/>
{/* Angle Text */}
<text
x={cx + 20}
y={cy - 10}
className="text-xs font-bold fill-orange-600"
>
{angle}°
</text>
{/* Radius Text */}
<text
x={cx + radius / 2}
y={cy + 15}
textAnchor="middle"
className="text-xs font-bold fill-slate-400"
>
r = {Math.round(radius / 10)}
</text>
{/* Center */}
<circle cx={cx} cy={cy} r={4} fill="#64748b" />
</svg>
</div>
<div className="flex-1 w-full space-y-6">
<div className="bg-orange-50 border border-orange-100 p-4 rounded-xl">
<h3 className="text-orange-900 font-bold mb-2 flex items-center gap-2">
<span className="p-1 bg-orange-200 rounded text-xs">INPUT</span>
Parameters
</h3>
<div className="space-y-4">
<div>
<div className="flex justify-between text-xs text-orange-700 uppercase font-bold mb-1">
Angle (θ): {angle}°
</div>
<input
type="range"
min="1"
max="360"
value={angle}
onChange={(e) => setAngle(parseInt(e.target.value))}
className="w-full h-2 bg-orange-200 rounded-lg appearance-none cursor-pointer accent-orange-600"
/>
</div>
<div>
<div className="flex justify-between text-xs text-orange-700 uppercase font-bold mb-1">
Radius (r): {Math.round(radius / 10)}
</div>
<input
type="range"
min="50"
max={maxRadius}
value={radius}
onChange={(e) => setRadius(parseInt(e.target.value))}
className="w-full h-2 bg-orange-200 rounded-lg appearance-none cursor-pointer accent-orange-600"
/>
</div>
</div>
</div>
<div className="space-y-4">
<div className="p-4 bg-white border border-slate-200 rounded-xl shadow-sm">
<div className="flex justify-between items-center mb-1">
<span className="text-sm font-bold text-slate-600">
Fraction of Circle
</span>
<span className="font-mono text-orange-600 font-bold">
{angle}/360 {(angle / 360).toFixed(2)}
</span>
</div>
<div className="w-full bg-slate-100 rounded-full h-2">
<div
className="bg-orange-500 h-2 rounded-full transition-all"
style={{ width: `${(angle / 360) * 100}%` }}
></div>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div className="p-4 bg-white border border-slate-200 rounded-xl shadow-sm">
<span className="text-xs font-bold text-slate-400 uppercase">
Arc Length
</span>
<div className="font-mono text-lg text-slate-800 mt-1">
2π({Math.round(radius / 10)}) ×{" "}
<span className="text-orange-600">
{(angle / 360).toFixed(2)}
</span>
</div>
<div className="font-bold text-xl text-slate-900 mt-1">
= {(2 * Math.PI * (radius / 10) * (angle / 360)).toFixed(1)}
</div>
</div>
<div className="p-4 bg-white border border-slate-200 rounded-xl shadow-sm">
<span className="text-xs font-bold text-slate-400 uppercase">
Sector Area
</span>
<div className="font-mono text-lg text-slate-800 mt-1">
π({Math.round(radius / 10)})² ×{" "}
<span className="text-orange-600">
{(angle / 360).toFixed(2)}
</span>
</div>
<div className="font-bold text-xl text-slate-900 mt-1">
={" "}
{(Math.PI * Math.pow(radius / 10, 2) * (angle / 360)).toFixed(
1,
)}
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default InteractiveSectorWidget;

View File

@ -0,0 +1,186 @@
import React, { useState } from 'react';
type Relationship = 'none' | 'vertical' | 'linear' | 'corresponding' | 'alt-interior' | 'same-side';
const InteractiveTransversal: React.FC = () => {
const [activeRel, setActiveRel] = useState<Relationship>('same-side');
// SVG Config
const width = 500;
const height = 300;
const line1Y = 100;
const line2Y = 200;
// Transversal passes through (200, 100) and (300, 200)
// Slope is 1 (45 degrees down-right)
const intersection1 = { x: 200, y: 100 };
const intersection2 = { x: 300, y: 200 };
// Angle Definitions (SVG y-down coordinates)
// 0 deg = Right, 90 deg = Down, 180 deg = Left, 270 deg = Up
// Transversal vector is (1, 1), angle is 45 deg.
// Opposite ray is 225 deg.
const angles = [
// Intersection 1 (Top)
{ id: 1, cx: intersection1.x, cy: intersection1.y, start: 180, end: 225, labelPos: 202.5, quadrant: 'TL' }, // Top-Left (Acute)
{ id: 2, cx: intersection1.x, cy: intersection1.y, start: 225, end: 360, labelPos: 292.5, quadrant: 'TR' }, // Top-Right (Obtuse)
{ id: 3, cx: intersection1.x, cy: intersection1.y, start: 0, end: 45, labelPos: 22.5, quadrant: 'BR' }, // Bottom-Right (Acute)
{ id: 4, cx: intersection1.x, cy: intersection1.y, start: 45, end: 180, labelPos: 112.5, quadrant: 'BL' }, // Bottom-Left (Obtuse)
// Intersection 2 (Bottom)
{ id: 5, cx: intersection2.x, cy: intersection2.y, start: 180, end: 225, labelPos: 202.5, quadrant: 'TL' },
{ id: 6, cx: intersection2.x, cy: intersection2.y, start: 225, end: 360, labelPos: 292.5, quadrant: 'TR' },
{ id: 7, cx: intersection2.x, cy: intersection2.y, start: 0, end: 45, labelPos: 22.5, quadrant: 'BR' },
{ id: 8, cx: intersection2.x, cy: intersection2.y, start: 45, end: 180, labelPos: 112.5, quadrant: 'BL' },
];
const getArcPath = (cx: number, cy: number, r: number, startDeg: number, endDeg: number) => {
// Convert to radians
const startRad = (startDeg * Math.PI) / 180;
const endRad = (endDeg * Math.PI) / 180;
const x1 = cx + r * Math.cos(startRad);
const y1 = cy + r * Math.sin(startRad);
const x2 = cx + r * Math.cos(endRad);
const y2 = cy + r * Math.sin(endRad);
const largeArc = (endDeg - startDeg) > 180 ? 1 : 0;
return `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${largeArc} 1 ${x2} ${y2} Z`;
};
const getLabelPos = (cx: number, cy: number, r: number, angleDeg: number) => {
const rad = (angleDeg * Math.PI) / 180;
return {
x: cx + r * Math.cos(rad),
y: cy + r * Math.sin(rad)
};
};
const getStyles = (id: number) => {
const base = { fill: 'transparent', stroke: 'transparent', label: 'text-slate-400' };
const highlightBlue = { fill: 'rgba(99, 102, 241, 0.3)', stroke: '#4f46e5', label: 'text-indigo-600 font-bold' };
const highlightPink = { fill: 'rgba(244, 63, 94, 0.3)', stroke: '#e11d48', label: 'text-rose-600 font-bold' };
switch (activeRel) {
case 'vertical':
// 1 & 3 are equal
if ([1, 3].includes(id)) return highlightBlue;
return base;
case 'linear':
// 1 & 2 are supplementary
if (id === 1) return highlightBlue;
if (id === 2) return highlightPink;
return base;
case 'corresponding':
// 2 & 6 are equal
if ([2, 6].includes(id)) return highlightBlue;
return base;
case 'alt-interior':
// 4 & 6 are equal
if ([4, 6].includes(id)) return highlightBlue;
return base;
case 'same-side':
// 3 & 6 are supplementary
if (id === 3) return highlightBlue;
if (id === 6) return highlightPink;
return base;
default:
return base;
}
};
const getDescription = () => {
switch (activeRel) {
case 'vertical': return "Vertical Angles are equal (e.g. ∠1 = ∠3)";
case 'linear': return "Linear Pairs sum to 180° (e.g. ∠1 + ∠2 = 180°)";
case 'corresponding': return "Corresponding Angles are equal (e.g. ∠2 = ∠6)";
case 'alt-interior': return "Alternate Interior Angles are equal (e.g. ∠4 = ∠6)";
case 'same-side': return "Same-Side Interior sum to 180° (e.g. ∠3 + ∠6 = 180°)";
default: return "Select a relationship to highlight";
}
};
const buttons: { id: Relationship, label: string }[] = [
{ id: 'vertical', label: 'Vertical Angles' },
{ id: 'linear', label: 'Linear Pair' },
{ id: 'corresponding', label: 'Corresponding' },
{ id: 'alt-interior', label: 'Alt. Interior' },
{ id: 'same-side', label: 'Same-Side Interior' },
];
return (
<div className="flex flex-col items-center bg-white p-8 rounded-xl shadow-sm border border-slate-200">
<div className="flex flex-wrap gap-2 justify-center mb-8">
{buttons.map(btn => (
<button
key={btn.id}
onClick={() => setActiveRel(activeRel === btn.id ? 'none' : btn.id)}
className={`px-4 py-2 rounded-full text-sm font-bold transition-all border ${
activeRel === btn.id
? 'bg-slate-900 text-white border-slate-900 shadow-md'
: 'bg-white text-slate-600 border-slate-200 hover:border-slate-400 hover:bg-slate-50'
}`}
>
{btn.label}
</button>
))}
</div>
<div className="relative w-full flex justify-center">
<div className="absolute top-0 left-0 w-full text-center">
<p className="text-slate-500 font-medium">{getDescription()}</p>
</div>
<svg width={width} height={height} className="mt-8 select-none">
<defs>
<marker id="arrow" markerWidth="12" markerHeight="12" refX="10" refY="4" orient="auto">
<path d="M0,0 L0,8 L12,4 z" fill="#64748b" />
</marker>
</defs>
{/* Parallel Lines */}
<line x1="50" y1={line1Y} x2="450" y2={line1Y} stroke="#64748b" strokeWidth="3" markerEnd="url(#arrow)" />
<line x1="450" y1={line1Y} x2="50" y2={line1Y} stroke="#64748b" strokeWidth="3" markerEnd="url(#arrow)" />
<line x1="50" y1={line2Y} x2="450" y2={line2Y} stroke="#64748b" strokeWidth="3" markerEnd="url(#arrow)" />
<line x1="450" y1={line2Y} x2="50" y2={line2Y} stroke="#64748b" strokeWidth="3" markerEnd="url(#arrow)" />
{/* Transversal (infinite line simulation) */}
<line x1="100" y1="0" x2="400" y2="300" stroke="#0f172a" strokeWidth="3" strokeLinecap="round" />
{/* Angles */}
{angles.map((angle) => {
const styles = getStyles(angle.id);
const r = 35;
const labelPos = getLabelPos(angle.cx, angle.cy, r + 15, angle.labelPos);
return (
<g key={angle.id}>
<path
d={getArcPath(angle.cx, angle.cy, r, angle.start, angle.end)}
fill={styles.fill}
stroke={styles.stroke}
strokeWidth={styles.stroke === 'transparent' ? 0 : 2}
/>
<text
x={labelPos.x}
y={labelPos.y}
textAnchor="middle"
dominantBaseline="middle"
className={`text-sm select-none ${styles.label}`}
>
{angle.id}
</text>
</g>
);
})}
</svg>
</div>
</div>
);
};
export default InteractiveTransversal;

View File

@ -0,0 +1,236 @@
import React, { useState, useRef, useEffect } from 'react';
// Helper to convert radians to degrees
const toDeg = (rad: number) => (rad * 180) / Math.PI;
const InteractiveTriangle: React.FC = () => {
// Vertex B state (the draggable top vertex)
// Default position forming a nice scalene triangle
const [bPos, setBPos] = useState({ x: 120, y: 50 });
const [isDragging, setIsDragging] = useState(false);
const [showProof, setShowProof] = useState(false);
const svgRef = useRef<SVGSVGElement>(null);
// Fixed vertices
const A = { x: 50, y: 250 };
const C = { x: 300, y: 250 };
const D = { x: 450, y: 250 }; // Extension of base AC
// Colors
const colors = {
A: { text: "text-indigo-600", stroke: "#4f46e5", fill: "rgba(79, 70, 229, 0.2)" },
B: { text: "text-emerald-600", stroke: "#059669", fill: "rgba(5, 150, 105, 0.2)" },
Ext: { text: "text-rose-600", stroke: "#e11d48", fill: "rgba(225, 29, 72, 0.2)" }
};
// Drag logic
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
if (!isDragging || !svgRef.current) return;
const rect = svgRef.current.getBoundingClientRect();
let x = e.clientX - rect.left;
let y = e.clientY - rect.top;
// Constraints
x = Math.max(20, Math.min(x, 380));
y = Math.max(20, Math.min(y, 230)); // Keep B above the base (y < 250)
setBPos({ x, y });
};
const handleMouseUp = () => setIsDragging(false);
if (isDragging) {
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
}
return () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseup', handleMouseUp);
};
}, [isDragging]);
// Calculations
// SVG Coordinate system: Y is Down.
// We use atan2(dy, dx) to get angles.
// Angle of vector (dx, dy).
// Angle of AB
const angleAB_rad = Math.atan2(bPos.y - A.y, bPos.x - A.x);
const angleAB_deg = toDeg(angleAB_rad); // usually negative (e.g. -60)
// Angle of AC is 0.
// Angle A (magnitude)
const valA = Math.abs(angleAB_deg);
// Angle of CB
const angleCB_rad = Math.atan2(bPos.y - C.y, bPos.x - C.x);
const angleCB_deg = toDeg(angleCB_rad); // usually negative (e.g. -120)
// Angle of CA is 180.
// Angle C Interior (magnitude) = 180 - abs(angleCB_deg) if y < C.y (which it is).
const valC = 180 - Math.abs(angleCB_deg);
// Angle B (Interior)
const valB = 180 - valA - valC;
// Exterior Angle (magnitude)
// Between CD (0) and CB (angleCB_deg).
// Ext = abs(angleCB_deg).
const valExt = Math.abs(angleCB_deg);
// Arc Generation Helper
const getArcPath = (cx: number, cy: number, r: number, startDeg: number, endDeg: number) => {
// SVG standard: degrees clockwise from X-axis.
// Our atan2 returns degrees relative to X-axis (clockwise positive if Y down).
// so we can use them directly.
const startRad = (startDeg * Math.PI) / 180;
const endRad = (endDeg * Math.PI) / 180;
const x1 = cx + r * Math.cos(startRad);
const y1 = cy + r * Math.sin(startRad);
const x2 = cx + r * Math.cos(endRad);
const y2 = cy + r * Math.sin(endRad);
// Sweep flag: 0 if counter-clockwise, 1 if clockwise.
// We want to draw from start to end.
// If we go from negative angle (AB) to 0 (AC), difference is positive.
const largeArc = Math.abs(endDeg - startDeg) > 180 ? 1 : 0;
const sweep = endDeg > startDeg ? 1 : 0;
return `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${largeArc} ${sweep} ${x2} ${y2} Z`;
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200 flex flex-col items-center select-none">
<div className="w-full flex justify-between items-center mb-4 px-2">
<h3 className="font-bold text-slate-700">Interactive Triangle</h3>
<label className="flex items-center gap-2 text-sm cursor-pointer hover:bg-slate-50 p-2 rounded transition-colors">
<input
type="checkbox"
checked={showProof}
onChange={(e) => setShowProof(e.target.checked)}
className="rounded text-indigo-600 focus:ring-indigo-500"
/>
<span className="font-medium text-slate-600">Show Proof (Parallel Line)</span>
</label>
</div>
<svg ref={svgRef} width="500" height="300" className="cursor-default">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto" markerUnits="strokeWidth">
<path d="M0,0 L0,6 L9,3 z" fill="#94a3b8" />
</marker>
</defs>
{/* Base Line Extension */}
<line x1={C.x} y1={C.y} x2={D.x} y2={D.y} stroke="#cbd5e1" strokeWidth="2" strokeDasharray="6,6" />
<text x={D.x} y={D.y + 20} fontSize="12" fill="#94a3b8">D</text>
{/* Angle Arcs */}
{/* Angle A: from angleAB to 0 */}
<path
d={getArcPath(A.x, A.y, 40, angleAB_deg, 0)}
fill={colors.A.fill} stroke={colors.A.stroke} strokeWidth="1"
/>
<text x={A.x + 50} y={A.y - 10} className={`text-xs font-bold ${colors.A.text}`} style={{opacity: 0.8}}>{Math.round(valA)}°</text>
{/* Angle B: from angle of BA to angle of BC */}
{/* Angle of BA is angleAB + 180. Angle of BC is angleCB + 180. */}
{/* Wait, B is center. */}
{/* Vector BA: A - B. Angle = atan2(Ay - By, Ax - Bx). */}
{/* Vector BC: C - B. Angle = atan2(Cy - By, Cx - Bx). */}
<path
d={getArcPath(bPos.x, bPos.y, 40, Math.atan2(A.y - bPos.y, A.x - bPos.x) * 180/Math.PI, Math.atan2(C.y - bPos.y, C.x - bPos.x) * 180/Math.PI)}
fill={colors.B.fill} stroke={colors.B.stroke} strokeWidth="1"
/>
{/* Label B slightly above vertex */}
<text x={bPos.x} y={bPos.y - 15} textAnchor="middle" className={`text-xs font-bold ${colors.B.text}`} style={{opacity: 0.8}}>{Math.round(valB)}°</text>
{/* Exterior Angle: at C, from angleCB to 0 */}
{/* If showing proof, split it */}
{!showProof && (
<path
d={getArcPath(C.x, C.y, 50, angleCB_deg, 0)}
fill={colors.Ext.fill} stroke={colors.Ext.stroke} strokeWidth="1"
/>
)}
{/* Proof Visuals */}
{showProof && (
<>
{/* Parallel Line CE. Angle same as AB: angleAB_deg */}
<line
x1={C.x} y1={C.y}
x2={C.x + 100 * Math.cos(angleAB_rad)} y2={C.y + 100 * Math.sin(angleAB_rad)}
stroke="#cbd5e1" strokeWidth="2" strokeDasharray="4,4"
/>
<text x={C.x + 110 * Math.cos(angleAB_rad)} y={C.y + 110 * Math.sin(angleAB_rad)} fontSize="12" fill="#94a3b8">E</text>
{/* Lower part of Ext (Corresponding to A) - From angleAB_deg to 0 */}
<path
d={getArcPath(C.x, C.y, 50, angleAB_deg, 0)}
fill={colors.A.fill} stroke={colors.A.stroke} strokeWidth="1"
/>
<text x={C.x + 60} y={C.y - 10} className={`text-xs font-bold ${colors.A.text}`}>{Math.round(valA)}°</text>
{/* Upper part of Ext (Alt Interior to B) - From angleCB_deg to angleAB_deg */}
<path
d={getArcPath(C.x, C.y, 50, angleCB_deg, angleAB_deg)}
fill={colors.B.fill} stroke={colors.B.stroke} strokeWidth="1"
/>
<text x={C.x + 35} y={C.y - 50} className={`text-xs font-bold ${colors.B.text}`}>{Math.round(valB)}°</text>
</>
)}
{/* Label Ext if not split or just general label */}
{!showProof && (
<text x={C.x + 60} y={C.y - 30} className={`text-sm font-bold ${colors.Ext.text}`}>Ext {Math.round(valExt)}°</text>
)}
{/* Triangle Lines */}
<path d={`M ${A.x} ${A.y} L ${bPos.x} ${bPos.y} L ${C.x} ${C.y} Z`} fill="none" stroke="#1e293b" strokeWidth="2" strokeLinejoin="round" />
{/* Vertices */}
<circle cx={A.x} cy={A.y} r="4" fill="#1e293b" />
<text x={A.x - 15} y={A.y + 5} fontSize="14" fontWeight="bold" fill="#334155">A</text>
<circle cx={C.x} cy={C.y} r="4" fill="#1e293b" />
<text x={C.x + 5} y={C.y + 20} fontSize="14" fontWeight="bold" fill="#334155">C</text>
{/* Draggable B */}
<g
onMouseDown={() => setIsDragging(true)}
className="cursor-grab active:cursor-grabbing"
>
<circle cx={bPos.x} cy={bPos.y} r="12" fill="transparent" /> {/* Hit area */}
<circle cx={bPos.x} cy={bPos.y} r="6" fill="#4f46e5" stroke="white" strokeWidth="2" className="shadow-sm" />
<text x={bPos.x} y={bPos.y - 20} textAnchor="middle" fontSize="14" fontWeight="bold" fill="#334155">B</text>
</g>
</svg>
<div className="w-full mt-4 p-4 bg-slate-50 rounded-lg border border-slate-100 flex flex-col items-center">
<div className="flex items-center gap-4 text-lg font-mono">
<span className={colors.Ext.text}>Ext ({Math.round(valExt)}°)</span>
<span className="text-slate-400">=</span>
<span className={colors.A.text}>A ({Math.round(valA)}°)</span>
<span className="text-slate-400">+</span>
<span className={colors.B.text}>B ({Math.round(valB)}°)</span>
</div>
<p className="text-xs text-slate-400 mt-2">
{showProof
? "Notice how the parallel line 'transports' angle A and B to the exterior?"
: "Drag vertex B to see the values update."}
</p>
</div>
</div>
);
};
export default InteractiveTriangle;

View File

@ -0,0 +1,23 @@
// LessonRenderer.tsx
import { Suspense } from "react";
import { LESSON_COMPONENT_MAP } from "../FetchLessonPage";
import type { LessonId } from "../FetchLessonPage";
interface Props {
lessonId: LessonId;
}
export const LessonRenderer = ({ lessonId }: Props) => {
const LessonComponent = LESSON_COMPONENT_MAP[lessonId];
if (!LessonComponent) {
return <p>Lesson not found.</p>;
}
return (
<Suspense fallback={<p>Loading lesson...</p>}>
<LessonComponent />
</Suspense>
);
};

View File

@ -0,0 +1,499 @@
import React, { useRef, useState, useEffect } from "react";
import { Check, ChevronDown, ChevronUp, ChevronRight } from "lucide-react";
import type { PracticeQuestion } from "../../types/lesson";
import {
transformMathHtml,
isQuestionBroken,
} from "../../utils/mathHtmlTransform";
export interface SectionDef {
title: string;
icon: React.ComponentType<{ className?: string }>;
}
interface LessonShellProps {
title: string;
sections: SectionDef[];
color: "blue" | "violet" | "amber" | "emerald";
onFinish?: () => void;
children: React.ReactNode;
}
/* ─── colour palette for each category ─── */
const PALETTES = {
blue: {
activeBg: "bg-blue-600",
activeText: "text-blue-900",
pastBg: "bg-blue-400",
sidebarActive: "bg-white/80 shadow-md border border-blue-100",
dotBg: "bg-blue-100",
dotText: "text-blue-500",
glassClass: "glass-blue",
},
violet: {
activeBg: "bg-violet-600",
activeText: "text-violet-900",
pastBg: "bg-violet-400",
sidebarActive: "bg-white/80 shadow-md border border-violet-100",
dotBg: "bg-violet-100",
dotText: "text-violet-500",
glassClass: "glass-violet",
},
amber: {
activeBg: "bg-amber-600",
activeText: "text-amber-900",
pastBg: "bg-amber-400",
sidebarActive: "bg-white/80 shadow-md border border-amber-100",
dotBg: "bg-amber-100",
dotText: "text-amber-500",
glassClass: "glass-amber",
},
emerald: {
activeBg: "bg-emerald-600",
activeText: "text-emerald-900",
pastBg: "bg-emerald-400",
sidebarActive: "bg-white/80 shadow-md border border-emerald-100",
dotBg: "bg-emerald-100",
dotText: "text-emerald-500",
glassClass: "glass-emerald",
},
};
export default function LessonShell({
title,
sections,
color,
onFinish,
children,
}: LessonShellProps) {
const palette = PALETTES[color];
const [activeSection, setActiveSection] = useState(0);
const [sidebarOpen, setSidebarOpen] = useState(false);
const sectionsRef = useRef<(HTMLElement | null)[]>([]);
const scrollToSection = (index: number) => {
setActiveSection(index);
sectionsRef.current[index]?.scrollIntoView({
behavior: "smooth",
block: "start",
});
setSidebarOpen(false);
};
/* scroll-spy */
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const idx = sectionsRef.current.indexOf(
entry.target as HTMLElement,
);
if (idx !== -1) setActiveSection(idx);
}
});
},
{ rootMargin: "-20% 0px -60% 0px" },
);
sectionsRef.current.forEach((s) => {
if (s) observer.observe(s);
});
return () => observer.disconnect();
}, []);
/* Inject ref callbacks onto section-wrapper children */
const childArray = React.Children.toArray(children);
return (
<div className="flex flex-col lg:flex-row min-h-screen lesson-bg">
{/* ── Mobile toggle ── */}
<button
onClick={() => setSidebarOpen(!sidebarOpen)}
className="lg:hidden fixed bottom-4 right-4 z-50 flex items-center gap-2 px-4 py-2.5 rounded-full shadow-lg text-sm font-bold text-slate-700 bg-white"
>
{sidebarOpen ? (
<ChevronDown className="w-4 h-4" />
) : (
<ChevronUp className="w-4 h-4" />
)}
{sections[activeSection]?.title ?? "Sections"}
</button>
{/* ── Sidebar ── */}
<aside
className={`
${sidebarOpen ? "translate-y-0" : "translate-y-full lg:translate-y-0"}
fixed bottom-0 left-0 right-0 lg:top-20 lg:bottom-0 lg:left-0 lg:right-auto
w-full lg:w-64 z-40 lg:z-0
glass-sidebar p-4 lg:overflow-y-auto
transition-transform duration-300 ease-out
rounded-t-2xl lg:rounded-none
border-t lg:border-t-0 border-slate-200/50
`}
>
<p className="text-[10px] font-bold uppercase tracking-[0.2em] text-slate-400 mb-3 px-1 hidden lg:block">
Sections
</p>
<nav className="space-y-1.5 bg-white">
{sections.map((sec, i) => {
const isActive = activeSection === i;
const isPast = activeSection > i;
const Icon = sec.icon;
return (
<button
key={i}
onClick={() => scrollToSection(i)}
className={`flex items-center gap-3 p-2.5 w-full rounded-xl transition-all text-left ${
isActive ? palette.sidebarActive : "hover:bg-white/50"
}`}
>
<div
className={`w-7 h-7 rounded-lg flex items-center justify-center shrink-0 transition-colors ${
isActive
? `${palette.activeBg} text-white`
: isPast
? `${palette.pastBg} text-white`
: `${palette.dotBg} ${palette.dotText}`
}`}
>
{isPast ? (
<Check className="w-3.5 h-3.5" />
) : (
<Icon className="w-3.5 h-3.5" />
)}
</div>
<span
className={`text-xs font-semibold leading-tight ${isActive ? palette.activeText : "text-slate-600"}`}
>
{sec.title}
</span>
</button>
);
})}
</nav>
</aside>
{/* ── Main content ── */}
<div className="flex-1 max-w-4xl mx-auto w-full">
{childArray.map((child, i) => (
<section
key={i}
ref={(el) => {
sectionsRef.current[i] = el;
}}
className="min-h-[70vh] mb-20 pt-16 lg:pt-4"
>
{child}
{/* next-section / finish button */}
{i < sections.length - 1 ? (
<button
onClick={() => scrollToSection(i + 1)}
className={`mt-10 group flex items-center gap-2 font-bold transition-colors ${
color === "blue"
? "text-blue-600 hover:text-blue-800"
: color === "violet"
? "text-violet-600 hover:text-violet-800"
: color === "amber"
? "text-amber-600 hover:text-amber-800"
: "text-emerald-600 hover:text-emerald-800"
}`}
>
Next: {sections[i + 1]?.title}
<ChevronRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
</button>
) : onFinish ? (
<button
onClick={onFinish}
className="mt-10 px-8 py-3 rounded-xl bg-linear-to-r from-slate-800 to-slate-900 text-white font-bold shadow-lg hover:from-slate-700 hover:to-slate-800 transition-all hover:scale-[1.02]"
>
Complete Lesson
</button>
) : null}
</section>
))}
</div>
</div>
);
}
/* ─── Reusable concept-card wrapper ─── */
export function ConceptCard({
color = "blue",
children,
className = "",
}: {
color?: "blue" | "violet" | "amber" | "emerald";
children: React.ReactNode;
className?: string;
}) {
const glassClass =
color === "blue"
? "glass-blue"
: color === "violet"
? "glass-violet"
: color === "amber"
? "glass-amber"
: "glass-emerald";
return (
<div
className={`${glassClass} glass-card rounded-2xl p-6 mb-8 space-y-5 ${className}`}
>
{children}
</div>
);
}
/* ─── Formula display box ─── */
export function FormulaBox({
children,
className = "",
}: {
children: React.ReactNode;
className?: string;
}) {
return (
<div
className={`glass-formula text-center py-4 px-6 font-mono text-lg font-bold text-slate-800 ${className}`}
>
{children}
</div>
);
}
/* ─── Worked-example card ─── */
export function ExampleCard({
title,
color = "blue",
children,
}: {
title: string;
color?: "blue" | "violet" | "amber" | "emerald";
children: React.ReactNode;
}) {
const border =
color === "blue"
? "border-blue-200 bg-gradient-to-br from-blue-50/60 to-indigo-50/40"
: color === "violet"
? "border-violet-200 bg-gradient-to-br from-violet-50/60 to-purple-50/40"
: color === "amber"
? "border-amber-200 bg-gradient-to-br from-amber-50/60 to-orange-50/40"
: "border-emerald-200 bg-gradient-to-br from-emerald-50/60 to-green-50/40";
const titleColor =
color === "blue"
? "text-blue-800"
: color === "violet"
? "text-violet-800"
: color === "amber"
? "text-amber-800"
: "text-emerald-800";
return (
<div className={`rounded-xl border ${border} p-5`}>
<p className={`font-bold ${titleColor} mb-3`}>{title}</p>
<div className="font-mono text-sm space-y-1 text-slate-700">
{children}
</div>
</div>
);
}
/* ─── Tip / Warning card ─── */
export function TipCard({
type = "tip",
children,
}: {
type?: "tip" | "warning" | "remember";
children: React.ReactNode;
}) {
const style =
type === "warning"
? "bg-red-50/70 border-red-200 text-red-900"
: type === "remember"
? "bg-amber-50/70 border-amber-200 text-amber-900"
: "bg-blue-50/70 border-blue-200 text-blue-900";
const label =
type === "warning"
? "Common Mistake"
: type === "remember"
? "Remember"
: "SAT Tip";
return (
<div className={`rounded-xl border p-4 text-sm ${style}`}>
<p className="font-bold mb-1">{label}</p>
{children}
</div>
);
}
/* ─── Practice question from dataset ─── */
type PracticeColor =
| "blue"
| "violet"
| "amber"
| "emerald"
| "teal"
| "fuchsia"
| "rose"
| "purple";
export function PracticeFromDataset({
question,
color = "blue",
}: {
key?: React.Key;
question: PracticeQuestion;
color?: PracticeColor;
}) {
const [selected, setSelected] = useState<string | null>(null);
const [submitted, setSubmitted] = useState(false);
const [sprInput, setSprInput] = useState("");
const isCorrect =
question.type === "mcq"
? selected === question.correctAnswer
: (() => {
const u = sprInput.trim().toLowerCase();
const answers = question.correctAnswer
.split(",")
.map((a) => a.trim().toLowerCase());
if (answers.includes(u)) return true;
const toNum = (s: string): number | null => {
if (s.includes("/")) {
const p = s.split("/");
return p.length === 2
? parseFloat(p[0]) / parseFloat(p[1])
: null;
}
const n = parseFloat(s);
return isNaN(n) ? null : n;
};
const uN = toNum(u);
return (
uN !== null &&
answers.some((a) => {
const aN = toNum(a);
return aN !== null && Math.abs(uN - aN) < 0.0015;
})
);
})();
const handleSubmit = () => {
if (question.type === "mcq" && !selected) return;
if (question.type === "spr" && !sprInput.trim()) return;
setSubmitted(true);
};
const accentMap: Record<PracticeColor, string> = {
blue: "border-blue-500 bg-blue-50",
violet: "border-violet-500 bg-violet-50",
amber: "border-amber-500 bg-amber-50",
emerald: "border-emerald-500 bg-emerald-50",
teal: "border-teal-500 bg-teal-50",
fuchsia: "border-fuchsia-500 bg-fuchsia-50",
rose: "border-rose-500 bg-rose-50",
purple: "border-purple-500 bg-purple-50",
};
const accent = accentMap[color] ?? accentMap.blue;
// Skip broken questions
if (isQuestionBroken(question)) return null;
return (
<div className="glass-card rounded-2xl p-5 mb-6 space-y-4">
{/* Passage (EBRW questions) */}
{question.passage && (
<div className="bg-linear-to-b from-slate-50 to-white rounded-xl border border-slate-200 p-4 text-sm text-slate-700 leading-relaxed max-h-60 overflow-y-auto">
<p className="text-[10px] font-extrabold text-slate-400 uppercase tracking-widest mb-2">
Passage
</p>
<div dangerouslySetInnerHTML={{ __html: question.passage }} />
</div>
)}
{question.hasFigure && question.figureUrl && (
<img
src={question.figureUrl}
alt="Figure"
className="max-w-full max-h-80 mx-auto rounded-xl border border-slate-200"
/>
)}
<div
className="text-sm text-slate-700 leading-relaxed"
dangerouslySetInnerHTML={{
__html: transformMathHtml(question.questionHtml),
}}
/>
{question.type === "mcq" ? (
<div className="space-y-2">
{question.choices.map((c) => {
const isThis = selected === c.label;
let ring = "border-slate-200 hover:border-slate-300";
if (submitted && isThis)
ring = isCorrect
? "border-emerald-500 bg-emerald-50"
: "border-red-400 bg-red-50";
else if (submitted && c.label === question.correctAnswer)
ring = "border-emerald-500 bg-emerald-50";
else if (isThis) ring = accent;
const isTable = c.text.includes("<br><br>");
return (
<button
key={c.label}
onClick={() => !submitted && setSelected(c.label)}
disabled={submitted}
className={`w-full text-left flex items-center gap-3 p-3 rounded-xl border transition-all text-sm ${ring}`}
>
<span className="w-7 h-7 rounded-full border border-current flex items-center justify-center text-xs font-bold shrink-0">
{c.label}
</span>
<div
className={`flex-1 ${isTable ? "columns-2 gap-8" : ""}`}
dangerouslySetInnerHTML={{
__html: transformMathHtml(c.text),
}}
/>
</button>
);
})}
</div>
) : (
<input
type="text"
value={sprInput}
onChange={(e) => !submitted && setSprInput(e.target.value)}
disabled={submitted}
placeholder="Type your answer…"
className="w-full px-4 py-2.5 rounded-xl border border-slate-200 text-sm focus:outline-none focus:ring-2 focus:ring-blue-300"
/>
)}
{!submitted ? (
<button
onClick={handleSubmit}
className="px-5 py-2 rounded-xl bg-slate-800 text-white text-sm font-bold hover:bg-slate-700 transition-colors"
>
Check Answer
</button>
) : (
<div
className={`rounded-xl border p-4 text-sm ${isCorrect ? "bg-emerald-50/70 border-emerald-200" : "bg-slate-50 border-slate-200"}`}
>
<p
className={`font-bold mb-1 ${isCorrect ? "text-emerald-700" : "text-red-600"}`}
>
{isCorrect
? "Correct!"
: `Incorrect — the answer is ${question.correctAnswer}`}
</p>
<div
className="text-slate-600 leading-relaxed"
dangerouslySetInnerHTML={{
__html: transformMathHtml(question.explanation),
}}
/>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,111 @@
import React, { useState } from 'react';
const LinearQuadraticSystemWidget: React.FC = () => {
// Parabola: y = x^2
// Line: y = mx + b
const [m, setM] = useState(1);
const [b, setB] = useState(-2);
// System: x^2 = mx + b => x^2 - mx - b = 0
// Discriminant: D = (-m)^2 - 4(1)(-b) = m^2 + 4b
const disc = m*m + 4*b;
const numSolutions = disc > 0 ? 2 : disc === 0 ? 1 : 0;
// Visualization
const width = 300;
const height = 300;
const range = 5;
const scale = width / (range * 2);
const center = width / 2;
const toPx = (v: number, isY = false) => isY ? center - v * scale : center + v * scale;
const generateParabola = () => {
let d = "";
for (let x = -range; x <= range; x += 0.1) {
const y = x * x;
if (y > range) continue;
const px = toPx(x);
const py = toPx(y, true);
d += d ? ` L ${px} ${py}` : `M ${px} ${py}`;
}
return d;
};
const generateLine = () => {
const x1 = -range;
const y1 = m * x1 + b;
const x2 = range;
const y2 = m * x2 + b;
return `M ${toPx(x1)} ${toPx(y1, true)} L ${toPx(x2)} ${toPx(y2, true)}`;
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8">
<div className="w-full md:w-1/3 space-y-6">
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200">
<div className="text-xs font-bold text-slate-400 uppercase mb-2">System</div>
<div className="font-mono text-lg font-bold text-slate-800">
y = x² <br/>
y = {m}x {b >= 0 ? '+' : ''}{b}
</div>
</div>
<div className="space-y-4">
<div>
<label className="text-xs font-bold text-indigo-600 uppercase">Slope (m) = {m}</label>
<input type="range" min="-4" max="4" step="0.5" value={m} onChange={e => setM(parseFloat(e.target.value))} className="w-full h-2 bg-indigo-100 rounded-lg accent-indigo-600"/>
</div>
<div>
<label className="text-xs font-bold text-rose-600 uppercase">Intercept (b) = {b}</label>
<input type="range" min="-5" max="5" step="0.5" value={b} onChange={e => setB(parseFloat(e.target.value))} className="w-full h-2 bg-rose-100 rounded-lg accent-rose-600"/>
</div>
</div>
<div className={`p-4 rounded-xl border-l-4 ${numSolutions > 0 ? 'bg-emerald-50 border-emerald-500' : 'bg-rose-50 border-rose-500'}`}>
<div className="text-xs font-bold uppercase text-slate-500">Discriminant (m² + 4b)</div>
<div className="text-xl font-bold text-slate-800 my-1">{disc.toFixed(2)}</div>
<div className="text-sm font-bold">
{numSolutions === 0 && <span className="text-rose-600">No Solutions</span>}
{numSolutions === 1 && <span className="text-amber-600">1 Solution (Tangent)</span>}
{numSolutions === 2 && <span className="text-emerald-600">2 Solutions</span>}
</div>
</div>
</div>
<div className="flex-1 flex justify-center">
<div className="relative w-[300px] h-[300px] bg-white border border-slate-200 rounded-xl overflow-hidden">
<svg width="100%" height="100%" viewBox="0 0 300 300">
{/* Axes */}
<line x1="0" y1={center} x2={width} y2={center} stroke="#cbd5e1" strokeWidth="2" />
<line x1={center} y1="0" x2={center} y2={height} stroke="#cbd5e1" strokeWidth="2" />
{/* Parabola */}
<path d={generateParabola()} fill="none" stroke="#64748b" strokeWidth="3" />
{/* Line */}
<path d={generateLine()} fill="none" stroke="#4f46e5" strokeWidth="3" />
{/* Intersections */}
{numSolutions > 0 && (
<>
{disc === 0 ? (
<circle cx={toPx(m/2)} cy={toPx((m/2)**2, true)} r="5" fill="#10b981" stroke="white" strokeWidth="2" />
) : (
<>
<circle cx={toPx((m + Math.sqrt(disc))/2)} cy={toPx(((m + Math.sqrt(disc))/2)**2, true)} r="5" fill="#10b981" stroke="white" strokeWidth="2" />
<circle cx={toPx((m - Math.sqrt(disc))/2)} cy={toPx(((m - Math.sqrt(disc))/2)**2, true)} r="5" fill="#10b981" stroke="white" strokeWidth="2" />
</>
)}
</>
)}
</svg>
</div>
</div>
</div>
</div>
);
};
export default LinearQuadraticSystemWidget;

View File

@ -0,0 +1,140 @@
import React, { useState } from 'react';
const LinearSolutionsWidget: React.FC = () => {
// Model: ax + b = cx + d
const [a, setA] = useState(2);
const [b, setB] = useState(4);
const [c, setC] = useState(2);
const [d, setD] = useState(8);
const isParallel = a === c;
const isCoincident = isParallel && b === d;
// Calculate solution if not parallel
// ax + b = cx + d => (a-c)x = d-b => x = (d-b)/(a-c)
const intersectionX = isParallel ? 0 : (d - b) / (a - c);
const intersectionY = a * intersectionX + b;
// Visualization range
const range = 10;
const scale = 20; // 1 unit = 20px
const center = 150; // px
const toPx = (val: number, isY = false) => {
if (isY) return center - val * scale;
return center + val * scale;
};
const getLinePath = (slope: number, intercept: number) => {
const x1 = -range;
const y1 = slope * x1 + intercept;
const x2 = range;
const y2 = slope * x2 + intercept;
return `M ${toPx(x1)} ${toPx(y1, true)} L ${toPx(x2)} ${toPx(y2, true)}`;
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col gap-6">
<div className="flex justify-between items-center bg-slate-50 p-4 rounded-lg border border-slate-200">
<div className="font-mono text-xl text-blue-700 font-bold">
<span className="text-indigo-600">{a}x + {b}</span> = <span className="text-emerald-600">{c}x + {d}</span>
</div>
<div className={`px-3 py-1 rounded text-sm font-bold uppercase ${
isCoincident ? 'bg-green-100 text-green-800' :
isParallel ? 'bg-rose-100 text-rose-800' :
'bg-blue-100 text-blue-800'
}`}>
{isCoincident ? "Infinite Solutions" : isParallel ? "No Solution" : "One Solution"}
</div>
</div>
<div className="flex flex-col md:flex-row gap-8">
{/* Controls */}
<div className="w-full md:w-1/3 space-y-4">
<div className="space-y-2 p-3 bg-indigo-50 rounded-lg border border-indigo-100">
<p className="text-xs font-bold text-indigo-800 uppercase">Left Side (Line 1)</p>
<div>
<label className="text-xs text-slate-500">Slope (a): {a}</label>
<input type="range" min="-5" max="5" step="1" value={a} onChange={e => setA(Number(e.target.value))} className="w-full h-1 bg-indigo-200 rounded accent-indigo-600" />
</div>
<div>
<label className="text-xs text-slate-500">Intercept (b): {b}</label>
<input type="range" min="-10" max="10" step="1" value={b} onChange={e => setB(Number(e.target.value))} className="w-full h-1 bg-indigo-200 rounded accent-indigo-600" />
</div>
</div>
<div className="space-y-2 p-3 bg-emerald-50 rounded-lg border border-emerald-100">
<p className="text-xs font-bold text-emerald-800 uppercase">Right Side (Line 2)</p>
<div>
<label className="text-xs text-slate-500">Slope (c): {c}</label>
<input type="range" min="-5" max="5" step="1" value={c} onChange={e => setC(Number(e.target.value))} className="w-full h-1 bg-emerald-200 rounded accent-emerald-600" />
</div>
<div>
<label className="text-xs text-slate-500">Intercept (d): {d}</label>
<input type="range" min="-10" max="10" step="1" value={d} onChange={e => setD(Number(e.target.value))} className="w-full h-1 bg-emerald-200 rounded accent-emerald-600" />
</div>
</div>
</div>
{/* Graph */}
<div className="w-full md:flex-1 border border-slate-200 rounded-lg overflow-hidden relative h-[300px] bg-white">
<svg width="100%" height="100%" viewBox="0 0 300 300" className="absolute top-0 left-0">
<defs>
<pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse">
<path d="M 20 0 L 0 0 0 20" fill="none" stroke="#f1f5f9" strokeWidth="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid)" />
{/* Axes */}
<line x1="0" y1="150" x2="300" y2="150" stroke="#cbd5e1" strokeWidth="2" />
<line x1="150" y1="0" x2="150" y2="300" stroke="#cbd5e1" strokeWidth="2" />
{/* Lines */}
<path d={getLinePath(a, b)} stroke="#4f46e5" strokeWidth="3" fill="none" />
<path d={getLinePath(c, d)} stroke={isCoincident ? "#4f46e5" : "#10b981"} strokeWidth="3" strokeDasharray={isCoincident ? "5,5" : ""} fill="none" />
{/* Intersection Point */}
{!isParallel && (
<circle cx={toPx(intersectionX)} cy={toPx(intersectionY, true)} r="5" fill="#f43f5e" stroke="white" strokeWidth="2" />
)}
</svg>
{/* Labels */}
{!isParallel && (
<div className="absolute bottom-2 right-2 bg-white/90 p-2 rounded text-xs border border-slate-200 shadow-sm">
Intersection: ({intersectionX.toFixed(2)}, {intersectionY.toFixed(2)})
</div>
)}
</div>
</div>
{/* Logic Explanation */}
<div className="bg-slate-50 p-4 rounded-lg text-sm text-slate-700">
<p className="font-bold mb-1">Algebraic Check:</p>
<ul className="list-disc pl-5 space-y-1">
<li>Subtract {c}x from both sides: <span className="font-mono font-bold">{(a-c).toFixed(0)}x + {b} = {d}</span></li>
{a === c ? (
<>
<li><span className="text-rose-600 font-bold">0x</span> (Variables cancel!)</li>
<li>Remaining statement: <span className="font-mono font-bold">{b} = {d}</span></li>
<li className={`font-bold ${b === d ? 'text-green-600' : 'text-rose-600'}`}>
{b === d ? "TRUE (Identity) → Infinite Solutions" : "FALSE (Contradiction) → No Solution"}
</li>
</>
) : (
<>
<li>Variables do NOT cancel.</li>
<li><span className="font-mono">{(a-c).toFixed(0)}x = {d - b}</span></li>
<li>One unique solution exists.</li>
</>
)}
</ul>
</div>
</div>
</div>
);
};
export default LinearSolutionsWidget;

View File

@ -0,0 +1,120 @@
import React, { useState } from 'react';
const LinearTransformationWidget: React.FC = () => {
const [h, setH] = useState(0); // Horizontal shift (x - h)
const [k, setK] = useState(0); // Vertical shift + k
const [reflectX, setReflectX] = useState(false); // -f(x)
const [stretch, setStretch] = useState(1); // a * f(x)
// Base function f(x) = 0.5x
// Transformed g(x) = a * f(x - h) + k
// g(x) = a * (0.5 * (x - h)) + k
// Actually, let's use f(x) = x for simplicity, or 0.5x to show slope changes easier?
// PDF examples use general f(x). Let's use f(x) = x as base.
// g(x) = stretch * (x - h) + k. If reflectX is true, stretch becomes -stretch.
const effectiveStretch = reflectX ? -stretch : stretch;
const range = 10;
const scale = 20; // 20px per unit
const size = 300;
const center = size / 2;
const toPx = (v: number, isY = false) => isY ? center - v * scale : center + v * scale;
// Base: y = 0.5x (to make it distinct from diagonals)
const getBasePath = () => {
const m = 0.5;
const x1 = -range, x2 = range;
const y1 = m * x1;
const y2 = m * x2;
return `M ${toPx(x1)} ${toPx(y1, true)} L ${toPx(x2)} ${toPx(y2, true)}`;
};
const getTransformedPath = () => {
// f(x) = 0.5x
// g(x) = effectiveStretch * (0.5 * (x - h)) + k
const x1 = -range, x2 = range;
const y1 = effectiveStretch * (0.5 * (x1 - h)) + k;
const y2 = effectiveStretch * (0.5 * (x2 - h)) + k;
return `M ${toPx(x1)} ${toPx(y1, true)} L ${toPx(x2)} ${toPx(y2, true)}`;
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8">
<div className="w-full md:w-1/3 space-y-6">
<div className="p-4 bg-slate-50 border border-slate-200 rounded-xl font-mono text-sm">
<p className="text-slate-400 mb-2">Base: <span className="text-slate-600 font-bold">f(x) = 0.5x</span></p>
<p className="text-indigo-900 font-bold text-lg">
g(x) = {reflectX ? '-' : ''}{stretch !== 1 ? stretch : ''}f(x {h > 0 ? '-' : '+'} {Math.abs(h)}) {k >= 0 ? '+' : '-'} {Math.abs(k)}
</p>
</div>
<div className="space-y-4">
<div>
<label className="text-xs font-bold text-indigo-600 uppercase flex justify-between">
Horizontal Shift (h) <span>{h}</span>
</label>
<input
type="range" min="-5" max="5" step="1"
value={h} onChange={e => setH(parseInt(e.target.value))}
className="w-full h-2 bg-indigo-100 rounded-lg appearance-none cursor-pointer accent-indigo-600 mt-1"
/>
<div className="flex justify-between text-[10px] text-slate-400">
<span>Left (x+h)</span>
<span>Right (x-h)</span>
</div>
</div>
<div>
<label className="text-xs font-bold text-emerald-600 uppercase flex justify-between">
Vertical Shift (k) <span>{k}</span>
</label>
<input
type="range" min="-5" max="5" step="1"
value={k} onChange={e => setK(parseInt(e.target.value))}
className="w-full h-2 bg-emerald-100 rounded-lg appearance-none cursor-pointer accent-emerald-600 mt-1"
/>
</div>
<div className="flex items-center gap-4 pt-2">
<label className="flex items-center gap-2 text-sm font-bold text-slate-700 cursor-pointer">
<input type="checkbox" checked={reflectX} onChange={e => setReflectX(e.target.checked)} className="accent-rose-600 w-4 h-4"/>
Reflect (-f(x))
</label>
</div>
</div>
</div>
<div className="flex-1 flex justify-center">
<div className="relative w-[300px] h-[300px] border border-slate-200 rounded-xl overflow-hidden bg-white">
<svg width="300" height="300" viewBox="0 0 300 300">
<defs>
<pattern id="grid-t" width="20" height="20" patternUnits="userSpaceOnUse">
<path d="M 20 0 L 0 0 0 20" fill="none" stroke="#f1f5f9" strokeWidth="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid-t)" />
{/* Axes */}
<line x1="0" y1={center} x2={size} y2={center} stroke="#cbd5e1" strokeWidth="2" />
<line x1={center} y1="0" x2={center} y2={size} stroke="#cbd5e1" strokeWidth="2" />
{/* Base Function (Ghost) */}
<path d={getBasePath()} stroke="#94a3b8" strokeWidth="2" strokeDasharray="4,4" />
<text x="260" y={toPx(0.5*8, true) - 5} className="text-xs fill-slate-400 font-bold">f(x)</text>
{/* Transformed Function */}
<path d={getTransformedPath()} stroke="#4f46e5" strokeWidth="3" />
<text x="20" y="20" className="text-xs fill-indigo-600 font-bold">g(x)</text>
</svg>
</div>
</div>
</div>
</div>
);
};
export default LinearTransformationWidget;

View File

@ -0,0 +1,201 @@
import React, { useState } from 'react';
import { Check, RotateCcw, ArrowRight } from 'lucide-react';
const LiteralEquationWidget: React.FC = () => {
const [problemIdx, setProblemIdx] = useState(0);
const [step, setStep] = useState(0);
const problems = [
{
id: 'perimeter',
title: 'Perimeter Formula',
goal: 'Isolate W',
steps: [
{
startEq: <>P = 2L + 2<span className="text-indigo-600">W</span></>,
options: [
{ text: 'Subtract 2L', correct: true },
{ text: 'Divide by 2', correct: false }
],
feedback: 'Moved 2L to the other side.',
nextEq: <>P - 2L = 2<span className="text-indigo-600">W</span></>
},
{
startEq: <>P - 2L = 2<span className="text-indigo-600">W</span></>,
options: [
{ text: 'Divide by 2', correct: true },
{ text: 'Subtract 2', correct: false }
],
feedback: 'Solved!',
nextEq: <><span className="text-indigo-600">W</span> = <span className="inline-block align-middle text-center border-t border-slate-800 pt-1 leading-none"><span className="block pb-1">P - 2L</span>2</span></>
}
]
},
{
id: 'linear',
title: 'Slope-Intercept',
goal: 'Isolate x',
steps: [
{
startEq: <>y = m<span className="text-indigo-600">x</span> + b</>,
options: [
{ text: 'Subtract b', correct: true },
{ text: 'Divide by m', correct: false }
],
feedback: 'Isolated the x term.',
nextEq: <>y - b = m<span className="text-indigo-600">x</span></>
},
{
startEq: <>y - b = m<span className="text-indigo-600">x</span></>,
options: [
{ text: 'Divide by m', correct: true },
{ text: 'Subtract m', correct: false }
],
feedback: 'Solved!',
nextEq: <><span className="text-indigo-600">x</span> = <span className="inline-block align-middle text-center border-t border-slate-800 pt-1 leading-none"><span className="block pb-1">y - b</span>m</span></>
}
]
},
{
id: 'standard',
title: 'Standard Form',
goal: 'Isolate y',
steps: [
{
startEq: <>Ax + B<span className="text-indigo-600">y</span> = C</>,
options: [
{ text: 'Subtract Ax', correct: true },
{ text: 'Divide by B', correct: false }
],
feedback: 'Moved the x term away.',
nextEq: <>B<span className="text-indigo-600">y</span> = C - Ax</>
},
{
startEq: <>B<span className="text-indigo-600">y</span> = C - Ax</>,
options: [
{ text: 'Divide by B', correct: true },
{ text: 'Subtract B', correct: false }
],
feedback: 'Solved!',
nextEq: <><span className="text-indigo-600">y</span> = <span className="inline-block align-middle text-center border-t border-slate-800 pt-1 leading-none"><span className="block pb-1">C - Ax</span>B</span></>
}
]
},
{
id: 'physics',
title: 'Velocity Formula',
goal: 'Isolate a',
steps: [
{
startEq: <>v = u + <span className="text-indigo-600">a</span>t</>,
options: [
{ text: 'Subtract u', correct: true },
{ text: 'Divide by t', correct: false }
],
feedback: 'Isolated the term with a.',
nextEq: <>v - u = <span className="text-indigo-600">a</span>t</>
},
{
startEq: <>v - u = <span className="text-indigo-600">a</span>t</>,
options: [
{ text: 'Divide by t', correct: true },
{ text: 'Subtract t', correct: false }
],
feedback: 'Solved!',
nextEq: <><span className="text-indigo-600">a</span> = <span className="inline-block align-middle text-center border-t border-slate-800 pt-1 leading-none"><span className="block pb-1">v - u</span>t</span></>
}
]
}
];
const currentProb = problems[problemIdx];
const currentStepData = currentProb.steps[step];
const handleNextProblem = () => {
let next = Math.floor(Math.random() * problems.length);
while (next === problemIdx) {
next = Math.floor(Math.random() * problems.length);
}
setProblemIdx(next);
setStep(0);
};
const reset = () => {
setStep(0);
};
const handleOption = (isCorrect: boolean) => {
if (isCorrect) {
setStep(step + 1);
}
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex justify-between items-center mb-6">
<h4 className="font-bold text-slate-700 flex items-center gap-2">
<span className="w-6 h-6 rounded-full bg-indigo-100 text-indigo-700 flex items-center justify-center text-xs font-bold">Ex</span>
{currentProb.goal}
</h4>
<button onClick={reset} className="text-slate-400 hover:text-indigo-600 transition-colors" title="Reset this problem">
<RotateCcw className="w-4 h-4" />
</button>
</div>
<div className="text-center mb-8 h-32 flex flex-col items-center justify-center transition-all">
{step < 2 ? (
<div className="animate-fade-in">
<div className="text-3xl font-mono font-bold text-slate-800 mb-2">
{currentStepData.startEq}
</div>
{step === 1 && <p className="text-sm text-green-600 font-bold mb-2 animate-pulse">{problems[problemIdx].steps[0].feedback}</p>}
<p className="text-sm text-slate-500">
{step === 0 ? "What is the first step?" : "What is the next step?"}
</p>
</div>
) : (
<div className="animate-fade-in bg-green-50 p-6 rounded-xl border border-green-200 w-full">
<div className="text-3xl font-mono font-bold text-green-800 mb-2">
{currentProb.steps[1].nextEq}
</div>
<div className="flex items-center justify-center gap-2 text-green-700 font-bold">
<Check className="w-5 h-5" /> {currentProb.steps[1].feedback}
</div>
</div>
)}
</div>
<div className="grid grid-cols-2 gap-4">
{step < 2 ? (
<>
{currentStepData.options.map((opt, i) => (
<button
key={i}
onClick={() => handleOption(opt.correct)}
className={`p-4 rounded-xl border-2 transition-all text-left group ${
opt.correct
? 'bg-slate-50 border-slate-200 hover:border-indigo-400 hover:bg-indigo-50'
: 'bg-slate-50 border-slate-200 hover:border-slate-300 opacity-80'
}`}
>
<span className={`text-xs font-bold uppercase mb-1 block ${opt.correct ? 'text-indigo-400 group-hover:text-indigo-600' : 'text-slate-400'}`}>
Option {i+1}
</span>
<span className="font-bold text-slate-700 group-hover:text-indigo-900">{opt.text}</span>
</button>
))}
</>
) : (
<button
onClick={handleNextProblem}
className="col-span-2 p-4 bg-indigo-600 text-white font-bold rounded-xl hover:bg-indigo-700 transition-colors flex items-center justify-center gap-2 shadow-md hover:shadow-lg transform hover:-translate-y-0.5"
>
Try Another Problem <ArrowRight className="w-4 h-4" />
</button>
)}
</div>
</div>
);
};
export default LiteralEquationWidget;

View File

@ -0,0 +1,103 @@
import React, { useState } from 'react';
import { ArrowRight } from 'lucide-react';
const MultiStepPercentWidget: React.FC = () => {
const [start, setStart] = useState(100);
const [change1, setChange1] = useState(40); // +40%
const [change2, setChange2] = useState(-25); // -25%
const step1Val = start * (1 + change1/100);
const finalVal = step1Val * (1 + change2/100);
const overallChange = ((finalVal - start) / start) * 100;
const naiveChange = change1 + change2;
// Scale for visualization
const maxVal = Math.max(start, step1Val, finalVal, 150);
const getWidth = (val: number) => (val / maxVal) * 100;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8 mb-8">
<div className="w-full md:w-1/3 space-y-6">
<div>
<label className="text-xs font-bold text-slate-400 uppercase">Change 1 (Markup)</label>
<div className="flex items-center gap-3">
<input
type="range" min="-50" max="100" step="5"
value={change1} onChange={e => setChange1(parseInt(e.target.value))}
className="flex-1 accent-indigo-600"
/>
<span className="font-bold text-indigo-600 w-12 text-right">{change1 > 0 ? '+' : ''}{change1}%</span>
</div>
</div>
<div>
<label className="text-xs font-bold text-slate-400 uppercase">Change 2 (Discount)</label>
<div className="flex items-center gap-3">
<input
type="range" min="-50" max="50" step="5"
value={change2} onChange={e => setChange2(parseInt(e.target.value))}
className="flex-1 accent-rose-600"
/>
<span className="font-bold text-rose-600 w-12 text-right">{change2 > 0 ? '+' : ''}{change2}%</span>
</div>
</div>
</div>
<div className="flex-1 space-y-4">
{/* Step 0 */}
<div className="relative">
<div className="flex justify-between text-xs font-bold text-slate-400 mb-1">
<span>Start</span>
<span>${start}</span>
</div>
<div className="h-8 bg-slate-200 rounded-md" style={{ width: `${getWidth(start)}%` }}></div>
</div>
{/* Step 1 */}
<div className="relative">
<div className="flex justify-between text-xs font-bold text-indigo-500 mb-1">
<span>After {change1 > 0 ? '+' : ''}{change1}%</span>
<span>${step1Val.toFixed(2)}</span>
</div>
<div className="h-8 bg-indigo-100 rounded-md transition-all duration-500" style={{ width: `${getWidth(step1Val)}%` }}>
<div className="h-full bg-indigo-500 rounded-l-md" style={{ width: `${(start/step1Val)*100}%` }}></div>
</div>
</div>
{/* Step 2 */}
<div className="relative">
<div className="flex justify-between text-xs font-bold text-rose-500 mb-1">
<span>After {change2 > 0 ? '+' : ''}{change2}%</span>
<span>${finalVal.toFixed(2)}</span>
</div>
<div className="h-8 bg-rose-100 rounded-md transition-all duration-500" style={{ width: `${getWidth(finalVal)}%` }}>
<div className="h-full bg-rose-500 rounded-l-md" style={{ width: `${(step1Val/finalVal)*100}%` }}></div>
</div>
</div>
</div>
</div>
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200 grid grid-cols-2 gap-4 text-center">
<div>
<div className="text-xs font-bold text-slate-400 uppercase mb-1">The Trap (Additive)</div>
<div className="text-lg font-bold text-slate-400 line-through decoration-red-500 decoration-2">
{naiveChange > 0 ? '+' : ''}{naiveChange}%
</div>
<div className="text-[10px] text-slate-400">({change1} + {change2})</div>
</div>
<div>
<div className="text-xs font-bold text-emerald-600 uppercase mb-1">Actual Change</div>
<div className="text-2xl font-bold text-emerald-600">
{overallChange > 0 ? '+' : ''}{overallChange.toFixed(2)}%
</div>
<div className="text-[10px] text-emerald-600 font-mono">
1.{change1} × {1 + change2/100} = {(1 + change1/100) * (1 + change2/100)}
</div>
</div>
</div>
</div>
);
};
export default MultiStepPercentWidget;

View File

@ -0,0 +1,124 @@
import React, { useState } from 'react';
const MultiplicityWidget: React.FC = () => {
const [m1, setM1] = useState(1); // Multiplicity for (x+2)
const [m2, setM2] = useState(2); // Multiplicity for (x-1)
// f(x) = 0.1 * (x+2)^m1 * (x-1)^m2
// Scale factor to keep y-values reasonable for visualization
const width = 300;
const height = 200;
const rangeX = 4;
const scaleX = width / (rangeX * 2);
const centerX = width / 2;
const centerY = height / 2;
const scaleY = 15; // Vertical compression
const toPx = (x: number, y: number) => ({
x: centerX + x * scaleX,
y: centerY - y * scaleY
});
const generatePath = () => {
let d = "";
// f(x) scaling factor depends on degree to keep graph in view
const k = 0.5;
for (let x = -rangeX; x <= rangeX; x += 0.05) {
const y = k * Math.pow(x + 2, m1) * Math.pow(x - 1, m2);
if (Math.abs(y) > 100) continue; // Clip
const pos = toPx(x, y);
d += d ? ` L ${pos.x} ${pos.y}` : `M ${pos.x} ${pos.y}`;
}
return d;
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="mb-6 text-center">
<div className="inline-block bg-slate-50 p-4 rounded-xl border border-slate-200">
<span className="font-mono text-xl font-bold text-slate-800">
P(x) = (x + 2)<sup className="text-rose-600">{m1}</sup> (x - 1)<sup className="text-indigo-600">{m2}</sup>
</span>
</div>
</div>
<div className="flex flex-col md:flex-row gap-8 items-center">
<div className="w-full md:w-1/3 space-y-6">
<div>
<label className="text-xs font-bold text-rose-600 uppercase mb-2 block">Root x = -2</label>
<div className="flex gap-2">
<button
onClick={() => setM1(1)}
className={`flex-1 py-2 rounded-lg font-bold text-sm border transition-all ${m1 === 1 ? 'bg-rose-600 text-white border-rose-600' : 'bg-white text-slate-500 border-slate-200'}`}
>
Odd (1)
</button>
<button
onClick={() => setM1(2)}
className={`flex-1 py-2 rounded-lg font-bold text-sm border transition-all ${m1 === 2 ? 'bg-rose-600 text-white border-rose-600' : 'bg-white text-slate-500 border-slate-200'}`}
>
Even (2)
</button>
</div>
<p className="text-xs text-rose-600 mt-2 font-bold text-center">
{m1 % 2 !== 0 ? "CROSSES Axis" : "TOUCHES Axis"}
</p>
</div>
<div>
<label className="text-xs font-bold text-indigo-600 uppercase mb-2 block">Root x = 1</label>
<div className="flex gap-2">
<button
onClick={() => setM2(1)}
className={`flex-1 py-2 rounded-lg font-bold text-sm border transition-all ${m2 === 1 ? 'bg-indigo-600 text-white border-indigo-600' : 'bg-white text-slate-500 border-slate-200'}`}
>
Odd (1)
</button>
<button
onClick={() => setM2(2)}
className={`flex-1 py-2 rounded-lg font-bold text-sm border transition-all ${m2 === 2 ? 'bg-indigo-600 text-white border-indigo-600' : 'bg-white text-slate-500 border-slate-200'}`}
>
Even (2)
</button>
</div>
<p className="text-xs text-indigo-600 mt-2 font-bold text-center">
{m2 % 2 !== 0 ? "CROSSES Axis" : "TOUCHES Axis"}
</p>
</div>
</div>
<div className="flex-1 flex justify-center">
<div className="relative w-[300px] h-[200px] bg-white border border-slate-200 rounded-xl overflow-hidden">
<svg width="100%" height="100%" viewBox="0 0 300 200">
{/* Grid Lines */}
<defs>
<pattern id="grid-mult" width="37.5" height="20" patternUnits="userSpaceOnUse">
<path d="M 37.5 0 L 0 0 0 20" fill="none" stroke="#f1f5f9" strokeWidth="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid-mult)" />
{/* Axes */}
<line x1="0" y1={centerY} x2={width} y2={centerY} stroke="#94a3b8" strokeWidth="2" />
<line x1={centerX} y1="0" x2={centerX} y2={height} stroke="#94a3b8" strokeWidth="2" />
{/* Graph */}
<path d={generatePath()} fill="none" stroke="#8b5cf6" strokeWidth="3" />
{/* Roots */}
<circle cx={toPx(-2, 0).x} cy={toPx(-2, 0).y} r="5" fill="#e11d48" stroke="white" strokeWidth="2" />
<text x={toPx(-2, 0).x} y={toPx(-2, 0).y + 20} textAnchor="middle" className="text-xs font-bold fill-rose-600">-2</text>
<circle cx={toPx(1, 0).x} cy={toPx(1, 0).y} r="5" fill="#4f46e5" stroke="white" strokeWidth="2" />
<text x={toPx(1, 0).x} y={toPx(1, 0).y + 20} textAnchor="middle" className="text-xs font-bold fill-indigo-600">1</text>
</svg>
</div>
</div>
</div>
</div>
);
};
export default MultiplicityWidget;

View File

@ -0,0 +1,96 @@
import React, { useState } from 'react';
const ParabolaWidget: React.FC = () => {
const [a, setA] = useState(1);
const [h, setH] = useState(2);
const [k, setK] = useState(1);
// Viewport
const range = 10;
const size = 300;
const scale = 300 / (range * 2);
const center = size / 2;
const toPx = (v: number, isY = false) => isY ? center - v * scale : center + v * scale;
// Generate Path
const generatePath = () => {
const step = 0.5;
let d = "";
for (let x = -range; x <= range; x += step) {
const y = a * Math.pow(x - h, 2) + k;
// Clip if way out of bounds to avoid SVG issues
if (Math.abs(y) > range * 2) continue;
const px = toPx(x);
const py = toPx(y, true);
d += x === -range ? `M ${px} ${py}` : ` L ${px} ${py}`;
}
return d;
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8">
<div className="w-full md:w-1/3 space-y-6">
<div className="bg-slate-50 p-4 rounded-xl text-center border border-slate-200">
<div className="text-xs font-bold text-slate-400 uppercase mb-1">Vertex Form</div>
<div className="text-xl font-mono font-bold text-slate-800">
y = <span className="text-indigo-600">{a}</span>(x - <span className="text-emerald-600">{h}</span>)² + <span className="text-rose-600">{k}</span>
</div>
</div>
<div className="space-y-4">
<div>
<label className="text-xs font-bold text-indigo-600 uppercase flex justify-between">
Stretch (a) <span>{a}</span>
</label>
<input type="range" min="-3" max="3" step="0.5" value={a} onChange={e => setA(parseFloat(e.target.value))} className="w-full h-2 bg-indigo-100 rounded-lg accent-indigo-600"/>
</div>
<div>
<label className="text-xs font-bold text-emerald-600 uppercase flex justify-between">
H-Shift (h) <span>{h}</span>
</label>
<input type="range" min="-5" max="5" step="0.5" value={h} onChange={e => setH(parseFloat(e.target.value))} className="w-full h-2 bg-emerald-100 rounded-lg accent-emerald-600"/>
</div>
<div>
<label className="text-xs font-bold text-rose-600 uppercase flex justify-between">
V-Shift (k) <span>{k}</span>
</label>
<input type="range" min="-5" max="5" step="0.5" value={k} onChange={e => setK(parseFloat(e.target.value))} className="w-full h-2 bg-rose-100 rounded-lg accent-rose-600"/>
</div>
</div>
</div>
<div className="flex-1 flex justify-center">
<div className="relative w-[300px] h-[300px] bg-white border border-slate-200 rounded-xl overflow-hidden">
<svg width="100%" height="100%" viewBox="0 0 300 300">
<defs>
<pattern id="para-grid" width={scale} height={scale} patternUnits="userSpaceOnUse">
<path d={`M ${scale} 0 L 0 0 0 ${scale}`} fill="none" stroke="#f1f5f9" strokeWidth="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#para-grid)" />
{/* Axes */}
<line x1="0" y1={center} x2={size} y2={center} stroke="#cbd5e1" strokeWidth="2" />
<line x1={center} y1="0" x2={center} y2={size} stroke="#cbd5e1" strokeWidth="2" />
{/* Parabola */}
<path d={generatePath()} fill="none" stroke="#8b5cf6" strokeWidth="3" />
{/* Vertex */}
<circle cx={toPx(h)} cy={toPx(k, true)} r="5" fill="#e11d48" stroke="white" strokeWidth="2" />
<text x={toPx(h)} y={toPx(k, true) - 10} textAnchor="middle" className="text-xs font-bold fill-rose-600 bg-white">V({h}, {k})</text>
{/* Axis of Symmetry */}
<line x1={toPx(h)} y1="0" x2={toPx(h)} y2={size} stroke="#10b981" strokeWidth="1" strokeDasharray="4,4" opacity="0.5" />
</svg>
</div>
</div>
</div>
</div>
);
};
export default ParabolaWidget;

View File

@ -0,0 +1,113 @@
import React, { useState } from 'react';
const ParallelPerpendicularWidget: React.FC = () => {
const [slope, setSlope] = useState(2);
const [showParallel, setShowParallel] = useState(true);
const [showPerpendicular, setShowPerpendicular] = useState(true);
const range = 10;
const scale = 20; // 20px per unit
const size = 300;
const center = size / 2;
const toPx = (v: number, isY = false) => isY ? center - v * scale : center + v * scale;
const getLinePath = (m: number, b: number) => {
// Find two points on edges of view box (-range, +range)
// y = mx + b
// Need to clip lines to viewBox to be nice
const x1 = -range;
const y1 = m * x1 + b;
const x2 = range;
const y2 = m * x2 + b;
return `M ${toPx(x1)} ${toPx(y1, true)} L ${toPx(x2)} ${toPx(y2, true)}`;
};
const perpSlope = slope === 0 ? 1000 : -1 / slope; // Hack for vertical
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8">
<div className="w-full md:w-1/3 space-y-6">
<div className="p-4 bg-slate-50 border border-slate-200 rounded-xl">
<label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Reference Slope (m)</label>
<div className="flex items-center gap-4">
<input
type="range" min="-4" max="4" step="0.5"
value={slope} onChange={e => setSlope(parseFloat(e.target.value))}
className="flex-1 h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-indigo-600"
/>
<span className="font-mono font-bold text-indigo-700 w-12 text-right">{slope}</span>
</div>
</div>
<div className="space-y-3">
<button
onClick={() => setShowParallel(!showParallel)}
className={`w-full flex items-center justify-between p-3 rounded-lg border-2 transition-all ${
showParallel ? 'border-sky-500 bg-sky-50 text-sky-900' : 'border-slate-200 text-slate-400'
}`}
>
<span className="font-bold">Parallel</span>
<span className="font-mono text-sm">{showParallel ? `m = ${slope}` : 'Hidden'}</span>
</button>
<button
onClick={() => setShowPerpendicular(!showPerpendicular)}
className={`w-full flex items-center justify-between p-3 rounded-lg border-2 transition-all ${
showPerpendicular ? 'border-rose-500 bg-rose-50 text-rose-900' : 'border-slate-200 text-slate-400'
}`}
>
<span className="font-bold">Perpendicular</span>
<span className="font-mono text-sm">{showPerpendicular ? `m = ${slope === 0 ? 'Undef' : (-1/slope).toFixed(2)}` : 'Hidden'}</span>
</button>
</div>
<div className="text-xs text-slate-500 bg-slate-50 p-3 rounded">
<strong>Key Rule:</strong> Perpendicular slopes are negative reciprocals ($m$ vs $-1/m$). Their product is always -1.
</div>
</div>
<div className="flex-1 flex justify-center">
<div className="relative w-[300px] h-[300px] border border-slate-200 rounded-xl overflow-hidden bg-white">
<svg width="300" height="300" viewBox="0 0 300 300">
<defs>
<pattern id="grid-p" width="20" height="20" patternUnits="userSpaceOnUse">
<path d="M 20 0 L 0 0 0 20" fill="none" stroke="#f1f5f9" strokeWidth="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid-p)" />
{/* Axes */}
<line x1="0" y1={center} x2={size} y2={center} stroke="#cbd5e1" strokeWidth="2" />
<line x1={center} y1="0" x2={center} y2={size} stroke="#cbd5e1" strokeWidth="2" />
{/* Reference Line (Indigo) */}
<path d={getLinePath(slope, 0)} stroke="#4f46e5" strokeWidth="3" />
{/* Parallel Line (Sky) - Shifted up by 3 units */}
{showParallel && (
<path d={getLinePath(slope, 3)} stroke="#0ea5e9" strokeWidth="3" strokeDasharray="5,5" />
)}
{/* Perpendicular Line (Rose) - Through Origin */}
{showPerpendicular && (
<>
<path d={getLinePath(perpSlope, 0)} stroke="#e11d48" strokeWidth="3" />
{/* Right Angle Marker approx */}
<rect
x={center} y={center} width="15" height="15"
fill="rgba(225, 29, 72, 0.2)"
transform={`rotate(${-Math.atan(slope) * 180 / Math.PI} ${center} ${center})`}
/>
</>
)}
</svg>
</div>
</div>
</div>
</div>
);
};
export default ParallelPerpendicularWidget;

View File

@ -0,0 +1,69 @@
import React, { useState } from 'react';
const PercentChangeWidget: React.FC = () => {
const [original, setOriginal] = useState(100);
const [percent, setPercent] = useState(25); // -100 to 100
const multiplier = 1 + (percent / 100);
const newValue = original * multiplier;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="mb-8 space-y-4">
<div className="flex items-center justify-between">
<label className="text-sm font-bold text-slate-500 uppercase">Original Value</label>
<input
type="number" value={original} onChange={e => setOriginal(Number(e.target.value))}
className="w-24 p-1 border border-slate-300 rounded font-mono font-bold text-slate-700 text-right"
/>
</div>
<div>
<div className="flex justify-between mb-2">
<label className="text-sm font-bold text-slate-500 uppercase">Percent Change</label>
<span className={`font-bold font-mono ${percent >= 0 ? 'text-emerald-600' : 'text-rose-600'}`}>
{percent > 0 ? '+' : ''}{percent}%
</span>
</div>
<input
type="range" min="-50" max="100" step="5" value={percent}
onChange={e => setPercent(parseInt(e.target.value))}
className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-indigo-600"
/>
</div>
</div>
<div className="flex items-end justify-center gap-8 h-48 border-b border-slate-200 pb-0 mb-6">
{/* Original Bar */}
<div className="flex flex-col items-center gap-2 w-24">
<span className="font-bold text-slate-500">{original}</span>
<div className="w-full bg-slate-400 rounded-t-lg transition-all duration-500" style={{ height: '120px' }}></div>
<span className="text-xs font-bold text-slate-400 uppercase mt-2">Original</span>
</div>
{/* New Bar */}
<div className="flex flex-col items-center gap-2 w-24">
<span className={`font-bold ${percent >= 0 ? 'text-emerald-600' : 'text-rose-600'}`}>
{newValue.toFixed(1)}
</span>
<div
className={`w-full rounded-t-lg transition-all duration-500 ${percent >= 0 ? 'bg-emerald-500' : 'bg-rose-500'}`}
style={{ height: `${120 * multiplier}px` }}
></div>
<span className="text-xs font-bold text-slate-400 uppercase mt-2">New</span>
</div>
</div>
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200">
<h4 className="text-xs font-bold text-slate-400 uppercase mb-2">Formula</h4>
<div className="font-mono text-lg text-center text-slate-800">
New = Original × (1 {percent >= 0 ? '+' : '-'} <span className="text-indigo-600">{Math.abs(percent/100)}</span>)
</div>
<div className="font-mono text-xl font-bold text-center text-indigo-700 mt-2">
New = {original} × {multiplier.toFixed(2)}
</div>
</div>
</div>
);
};
export default PercentChangeWidget;

View File

@ -0,0 +1,98 @@
import React, { useState, useEffect } from 'react';
const PolygonWidget: React.FC = () => {
const [n, setN] = useState(5);
// Math
const interiorSum = (n - 2) * 180;
const eachInterior = Math.round((interiorSum / n) * 100) / 100;
const eachExterior = Math.round((360 / n) * 100) / 100;
// SVG Config
const width = 300;
const height = 300;
const cx = width / 2;
const cy = height / 2;
const r = 80;
// Generate points
const points = [];
for (let i = 0; i < n; i++) {
const angle = (i * 2 * Math.PI) / n - Math.PI / 2; // Start at top
points.push({
x: cx + r * Math.cos(angle),
y: cy + r * Math.sin(angle)
});
}
// Generate path string
const pathD = points.map((p, i) => (i === 0 ? `M ${p.x} ${p.y}` : `L ${p.x} ${p.y}`)).join(' ') + ' Z';
// Generate exterior lines (extensions)
const exteriorLines = points.map((p, i) => {
const nextP = points[(i + 1) % n];
// Vector from p to nextP
const dx = nextP.x - p.x;
const dy = nextP.y - p.y;
// Normalize and extend
const len = Math.sqrt(dx*dx + dy*dy);
const exLen = 40;
const exX = nextP.x + (dx/len) * exLen;
const exY = nextP.y + (dy/len) * exLen;
return { x1: nextP.x, y1: nextP.y, x2: exX, y2: exY };
});
return (
<div className="bg-white p-6 rounded-xl shadow-sm border border-slate-200 flex flex-col md:flex-row gap-8 items-center">
<div className="flex-1 w-full max-w-xs">
<label className="block text-sm font-bold text-slate-500 uppercase mb-2">Number of Sides (n): <span className="text-slate-900 text-lg">{n}</span></label>
<input
type="range" min="3" max="10" step="1"
value={n} onChange={(e) => setN(parseInt(e.target.value))}
className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-emerald-600 mb-6"
/>
<div className="space-y-3 font-mono text-sm">
<div className="p-3 bg-slate-50 rounded border border-slate-200">
<div className="text-xs text-slate-500 font-bold uppercase">Interior Sum</div>
<div className="text-slate-800">(n - 2) × 180° = <strong className="text-emerald-600">{interiorSum}°</strong></div>
</div>
<div className="p-3 bg-slate-50 rounded border border-slate-200">
<div className="text-xs text-slate-500 font-bold uppercase">Each Interior Angle</div>
<div className="text-slate-800">{interiorSum} / {n} = <strong className="text-emerald-600">{eachInterior}°</strong></div>
</div>
<div className="p-3 bg-slate-50 rounded border border-slate-200">
<div className="text-xs text-slate-500 font-bold uppercase">Each Exterior Angle</div>
<div className="text-slate-800">360 / {n} = <strong className="text-rose-600">{eachExterior}°</strong></div>
</div>
</div>
</div>
<div className="flex-shrink-0 relative">
<svg width={width} height={height}>
{/* Extensions for exterior angles */}
{exteriorLines.map((line, i) => (
<line key={i} x1={line.x1} y1={line.y1} x2={line.x2} y2={line.y2} stroke="#cbd5e1" strokeWidth="2" strokeDasharray="4,4" />
))}
{/* Polygon */}
<path d={pathD} fill="rgba(16, 185, 129, 0.1)" stroke="#059669" strokeWidth="3" />
{/* Vertices */}
{points.map((p, i) => (
<circle key={i} cx={p.x} cy={p.y} r="4" fill="#059669" />
))}
{/* Center text */}
<text x={cx} y={cy} textAnchor="middle" dominantBaseline="middle" fill="#059669" fontSize="24" fontWeight="bold" opacity="0.2">
{n}-gon
</text>
</svg>
</div>
</div>
);
};
export default PolygonWidget;

View File

@ -0,0 +1,77 @@
import React, { useState } from 'react';
const PolynomialBehaviorWidget: React.FC = () => {
const [degreeType, setDegreeType] = useState<'even' | 'odd'>('odd');
const [lcSign, setLcSign] = useState<'pos' | 'neg'>('pos');
// Visualization
const width = 300;
const height = 200;
const getPath = () => {
// Create schematic shapes
// Odd +: Low Left -> High Right
// Odd -: High Left -> Low Right
// Even +: High Left -> High Right
// Even -: Low Left -> Low Right
const startY = (degreeType === 'odd' && lcSign === 'pos') || (degreeType === 'even' && lcSign === 'neg') ? 180 : 20;
const endY = (lcSign === 'pos') ? 20 : 180;
// Control points for curvy polynomial look
const cp1Y = startY === 20 ? 150 : 50;
const cp2Y = endY === 20 ? 150 : 50;
return `M 20 ${startY} C 100 ${cp1Y}, 200 ${cp2Y}, 280 ${endY}`;
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="grid grid-cols-2 gap-4 mb-6">
<div className="space-y-2">
<p className="text-xs font-bold text-slate-400 uppercase">Degree (Highest Power)</p>
<div className="flex gap-2">
<button onClick={() => setDegreeType('even')} className={`px-4 py-2 rounded-lg font-bold text-sm border transition-all ${degreeType === 'even' ? 'bg-indigo-600 text-white border-indigo-600' : 'bg-white text-slate-600 border-slate-200'}`}>Even (x², x)</button>
<button onClick={() => setDegreeType('odd')} className={`px-4 py-2 rounded-lg font-bold text-sm border transition-all ${degreeType === 'odd' ? 'bg-indigo-600 text-white border-indigo-600' : 'bg-white text-slate-600 border-slate-200'}`}>Odd (x, x³)</button>
</div>
</div>
<div className="space-y-2">
<p className="text-xs font-bold text-slate-400 uppercase">Leading Coefficient</p>
<div className="flex gap-2">
<button onClick={() => setLcSign('pos')} className={`px-4 py-2 rounded-lg font-bold text-sm border transition-all ${lcSign === 'pos' ? 'bg-emerald-600 text-white border-emerald-600' : 'bg-white text-slate-600 border-slate-200'}`}>Positive (+)</button>
<button onClick={() => setLcSign('neg')} className={`px-4 py-2 rounded-lg font-bold text-sm border transition-all ${lcSign === 'neg' ? 'bg-rose-600 text-white border-rose-600' : 'bg-white text-slate-600 border-slate-200'}`}>Negative (-)</button>
</div>
</div>
</div>
<div className="relative h-48 bg-slate-50 border border-slate-200 rounded-xl overflow-hidden flex items-center justify-center">
<svg width="300" height="200">
<line x1="150" y1="20" x2="150" y2="180" stroke="#cbd5e1" strokeWidth="2" />
<line x1="20" y1="100" x2="280" y2="100" stroke="#cbd5e1" strokeWidth="2" />
<path d={getPath()} stroke="#8b5cf6" strokeWidth="4" fill="none" markerEnd="url(#arrow)" markerStart="url(#arrow-start)" />
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto">
<path d="M0,0 L0,6 L9,3 z" fill="#8b5cf6" />
</marker>
<marker id="arrow-start" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto-start-reverse">
<path d="M0,0 L0,6 L9,3 z" fill="#8b5cf6" />
</marker>
</defs>
</svg>
<div className="absolute top-2 left-2 text-xs font-bold text-slate-400">End Behavior</div>
</div>
<div className="mt-4 p-3 bg-indigo-50 border border-indigo-100 rounded-lg text-sm text-indigo-900 text-center">
{degreeType === 'even' && lcSign === 'pos' && "Ends go in the SAME direction (UP)."}
{degreeType === 'even' && lcSign === 'neg' && "Ends go in the SAME direction (DOWN)."}
{degreeType === 'odd' && lcSign === 'pos' && "Ends go in OPPOSITE directions (Down Left, Up Right)."}
{degreeType === 'odd' && lcSign === 'neg' && "Ends go in OPPOSITE directions (Up Left, Down Right)."}
</div>
</div>
);
};
export default PolynomialBehaviorWidget;

View File

@ -0,0 +1,364 @@
import React, { useState, useRef } from 'react';
type Mode = 'chords' | 'secants';
interface Point {
x: number;
y: number;
}
const PowerOfPointWidget: React.FC = () => {
const [mode, setMode] = useState<Mode>('chords');
// -- Common State --
const svgRef = useRef<SVGSVGElement>(null);
const isDragging = useRef<string | null>(null);
const center = { x: 200, y: 180 };
const radius = 100;
// -- Chords Mode State --
// Store angles for points A, B, C, D on the circle
const [chordAngles, setChordAngles] = useState({
a: 220, b: 40, // Chord 1
c: 140, d: 320 // Chord 2
});
// -- Secants Mode State --
// P is external point.
// Secant 1 defined by angle theta1 (offset from center-P line)
// Secant 2 defined by angle theta2
const [secantState, setSecantState] = useState({
px: 380, py: 180, // Point P
theta1: 15, // Angle offset for secant 1
});
// --- Helper Math ---
const getPosOnCircle = (deg: number) => ({
x: center.x + radius * Math.cos(deg * Math.PI / 180),
y: center.y + radius * Math.sin(deg * Math.PI / 180)
});
const dist = (p1: Point, p2: Point) => Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
const getIntersection = (p1: Point, p2: Point, p3: Point, p4: Point) => {
// Line AB represented as a1x + b1y = c1
const a1 = p2.y - p1.y;
const b1 = p1.x - p2.x;
const c1 = a1 * p1.x + b1 * p1.y;
// Line CD represented as a2x + b2y = c2
const a2 = p4.y - p3.y;
const b2 = p3.x - p4.x;
const c2 = a2 * p3.x + b2 * p3.y;
const determinant = a1 * b2 - a2 * b1;
if (Math.abs(determinant) < 0.001) return null; // Parallel
const x = (b2 * c1 - b1 * c2) / determinant;
const y = (a1 * c2 - a2 * c1) / determinant;
// Check if inside circle
if (dist({x,y}, center) > radius + 1) return null;
return { x, y };
};
// --- Interaction Handlers ---
const handleChordDrag = (e: React.MouseEvent, key: string) => {
if (!svgRef.current) return;
const rect = svgRef.current.getBoundingClientRect();
const dx = e.clientX - rect.left - center.x;
const dy = e.clientY - rect.top - center.y;
let deg = Math.atan2(dy, dx) * 180 / Math.PI;
if (deg < 0) deg += 360;
setChordAngles(prev => ({ ...prev, [key]: deg }));
};
const handleSecantDrag = (e: React.MouseEvent) => {
if (!svgRef.current) return;
const rect = svgRef.current.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
if (isDragging.current === 'P') {
// Constrain P outside
const dx = x - center.x;
const dy = y - center.y;
const d = Math.sqrt(dx*dx + dy*dy);
if (d > radius + 20) {
setSecantState(prev => ({...prev, px: x, py: y}));
} else {
const ang = Math.atan2(dy, dx);
setSecantState(prev => ({
...prev,
px: center.x + (radius+20)*Math.cos(ang),
py: center.y + (radius+20)*Math.sin(ang)
}));
}
} else if (isDragging.current === 'SecantEnd') {
// Calculate angle relative to PO line
// Vector PO
const pdx = center.x - secantState.px;
const pdy = center.y - secantState.py;
const poAngle = Math.atan2(pdy, pdx);
// Vector PA (mouse to P)
const mdx = x - secantState.px;
const mdy = y - secantState.py;
const mAngle = Math.atan2(mdy, mdx);
let diff = (mAngle - poAngle) * 180 / Math.PI;
// Normalize to -180 to 180
while (diff > 180) diff -= 360;
while (diff < -180) diff += 360;
// Clamp to hit circle. Max angle is asin(R/dist)
const distPO = Math.sqrt(pdx*pdx + pdy*pdy);
const maxAngle = Math.asin(radius/distPO) * 180 / Math.PI;
// Clamp
const clamped = Math.max(-maxAngle + 1, Math.min(maxAngle - 1, diff));
setSecantState(prev => ({...prev, theta1: clamped}));
}
};
// --- Render Helpers ---
const renderChords = () => {
const A = getPosOnCircle(chordAngles.a);
const B = getPosOnCircle(chordAngles.b);
const C = getPosOnCircle(chordAngles.c);
const D = getPosOnCircle(chordAngles.d);
const E = getIntersection(A, B, C, D);
const valid = !!E;
const ae = valid ? dist(A, E) : 0;
const eb = valid ? dist(E, B) : 0;
const ce = valid ? dist(C, E) : 0;
const ed = valid ? dist(E, D) : 0;
const points = [
{ k: 'a', p: A, l: 'A', c: '#7c3aed' },
{ k: 'b', p: B, l: 'B', c: '#7c3aed' },
{ k: 'c', p: C, l: 'C', c: '#059669' },
{ k: 'd', p: D, l: 'D', c: '#059669' }
];
return (
<>
<line x1={A.x} y1={A.y} x2={B.x} y2={B.y} stroke="#7c3aed" strokeWidth="3" />
<line x1={C.x} y1={C.y} x2={D.x} y2={D.y} stroke="#059669" strokeWidth="3" />
{/* Points */}
{points.map((pt) => (
<g key={pt.k} onMouseDown={() => isDragging.current = pt.k} className="cursor-pointer hover:scale-110 transition-transform">
<circle cx={pt.p.x} cy={pt.p.y} r="15" fill="transparent" />
<circle cx={pt.p.x} cy={pt.p.y} r="6" fill={pt.c} stroke="white" strokeWidth="2" />
<text x={pt.p.x} y={pt.p.y - 12} textAnchor="middle" className="text-sm font-bold fill-slate-700">{pt.l}</text>
</g>
))}
{valid && (
<>
<circle cx={E.x} cy={E.y} r="4" fill="#0f172a" />
<text x={E.x + 10} y={E.y} className="text-xs font-bold fill-slate-500">E</text>
</>
)}
{/* Info Panel */}
<div className="absolute top-4 left-4 bg-white/90 p-4 rounded-xl border border-slate-200 shadow-sm backdrop-blur-sm pointer-events-none select-none">
{!valid ? (
<p className="text-red-500 font-bold">Chords must intersect inside!</p>
) : (
<div className="space-y-3 font-mono text-sm">
<div className="flex gap-4">
<div>
<div className="text-xs font-bold text-violet-600">Purple Chord</div>
<div>{ae.toFixed(0)} × {eb.toFixed(0)} = <strong>{(ae*eb).toFixed(0)}</strong></div>
</div>
</div>
<div className="flex gap-4">
<div>
<div className="text-xs font-bold text-emerald-600">Green Chord</div>
<div>{ce.toFixed(0)} × {ed.toFixed(0)} = <strong>{(ce*ed).toFixed(0)}</strong></div>
</div>
</div>
<div className="h-px bg-slate-200"></div>
<p className="text-slate-500 text-xs text-center font-sans">
AE · EB = CE · ED
</p>
</div>
)}
</div>
</>
);
};
const renderSecant = () => {
const { px, py, theta1 } = secantState;
// Calculate Tangent Point T (Upper)
const dx = px - center.x;
const dy = py - center.y;
const distPO = Math.sqrt(dx*dx + dy*dy);
const anglePO = Math.atan2(dy, dx);
const angleOffset = Math.acos(radius/distPO);
const tAngle = anglePO - angleOffset;
const T = {
x: center.x + radius * Math.cos(tAngle),
y: center.y + radius * Math.sin(tAngle)
};
const tangentLen = Math.sqrt(distPO*distPO - radius*radius);
// Calculate Secant Intersection Points
// Secant Line angle
const secantAngle = anglePO + theta1 * Math.PI / 180;
const vx = px - center.x;
const vy = py - center.y;
const cos = Math.cos(secantAngle);
const sin = Math.sin(secantAngle);
// t^2 + 2(V.D)t + (V^2 - R^2) = 0
const b = 2 * (vx * cos + vy * sin);
const c = vx*vx + vy*vy - radius*radius;
const det = b*b - 4*c;
let A = {x:0, y:0}, B = {x:0, y:0};
let valid = false;
if (det > 0) {
const tFar = (-b - Math.sqrt(det)) / 2;
const tNear = (-b + Math.sqrt(det)) / 2;
// A is Near (External part)
A = { x: px + tNear * cos, y: py + tNear * sin };
// B is Far (Whole secant endpoint)
B = { x: px + tFar * cos, y: py + tFar * sin };
valid = true;
}
const distPA = valid ? dist({x:px, y:py}, A) : 0;
const distPB = valid ? dist({x:px, y:py}, B) : 0;
return (
<>
{/* Tangent Line */}
<line x1={px} y1={py} x2={T.x} y2={T.y} stroke="#e11d48" strokeWidth="3" />
<circle cx={T.x} cy={T.y} r="5" fill="#e11d48" />
<text x={T.x} y={T.y - 10} className="text-xs font-bold fill-rose-600">T</text>
{/* Secant Line (Draw full segment P to B) */}
{valid && <line x1={px} y1={py} x2={B.x} y2={B.y} stroke="#7c3aed" strokeWidth="3" />}
{valid && (
<>
{/* Point A (Near/External) */}
<circle cx={A.x} cy={A.y} r="5" fill="#7c3aed" />
<text x={A.x + 15} y={A.y} className="text-xs font-bold fill-violet-600">A</text>
{/* Point B (Far/Whole) */}
<circle cx={B.x} cy={B.y} r="5" fill="#7c3aed" />
<text x={B.x - 15} y={B.y} className="text-xs font-bold fill-violet-600">B</text>
</>
)}
{/* Point P */}
<g onMouseDown={() => isDragging.current = 'P'} className="cursor-grab active:cursor-grabbing">
<circle cx={px} cy={py} r="15" fill="transparent" />
<circle cx={px} cy={py} r="6" fill="#0f172a" stroke="white" strokeWidth="2" />
<text x={px + 10} y={py} className="text-sm font-bold fill-slate-800">P</text>
</g>
{/* Drag Handle for Secant Angle (at B, the far end) */}
{valid && (
<circle
cx={B.x} cy={B.y} r="12" fill="transparent" stroke="white" strokeWidth="2" strokeDasharray="2,2"
className="cursor-pointer hover:stroke-violet-400"
onMouseDown={() => isDragging.current = 'SecantEnd'}
/>
)}
{/* Info */}
<div className="absolute top-4 left-4 bg-white/90 p-4 rounded-xl border border-slate-200 shadow-sm backdrop-blur-sm pointer-events-none select-none">
<div className="space-y-3 font-mono text-sm">
<div className="mb-2">
<div className="text-xs font-bold text-rose-600 uppercase">Tangent² (PT²)</div>
<div>{tangentLen.toFixed(0)}² = <strong>{(tangentLen*tangentLen).toFixed(0)}</strong></div>
</div>
<div>
<div className="text-xs font-bold text-violet-600 uppercase">Secant (PA · PB)</div>
<div className="flex items-center gap-1">
<span title="External Part (PA)">{distPA.toFixed(0)}</span>
<span className="text-slate-400">×</span>
<span title="Whole Secant (PB)">{distPB.toFixed(0)}</span>
<span className="text-slate-400">=</span>
<strong>{(distPA*distPB).toFixed(0)}</strong>
</div>
</div>
<div className="h-px bg-slate-200 my-2"></div>
<p className="text-slate-500 text-xs text-center font-sans">
Tangent² = External × Whole
</p>
</div>
</div>
</>
);
};
const handleMouseMove = (e: React.MouseEvent) => {
if (!isDragging.current) return;
if (mode === 'chords') {
// Check if dragging specific points
if (['a','b','c','d'].includes(isDragging.current as string)) {
handleChordDrag(e, isDragging.current as string);
}
} else {
handleSecantDrag(e);
}
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex gap-4 mb-6 justify-center">
<button
onClick={() => setMode('chords')}
className={`px-4 py-2 rounded-full font-bold text-sm transition-all ${mode === 'chords' ? 'bg-slate-900 text-white shadow-md' : 'bg-slate-100 text-slate-500 hover:bg-slate-200'}`}
>
Intersecting Chords
</button>
<button
onClick={() => setMode('secants')}
className={`px-4 py-2 rounded-full font-bold text-sm transition-all ${mode === 'secants' ? 'bg-slate-900 text-white shadow-md' : 'bg-slate-100 text-slate-500 hover:bg-slate-200'}`}
>
Tangent-Secant
</button>
</div>
<div className="relative flex justify-center bg-slate-50 rounded-xl border border-slate-100 overflow-hidden">
<svg
ref={svgRef}
width="500" height="360"
className="select-none"
onMouseMove={handleMouseMove}
onMouseUp={() => isDragging.current = null}
onMouseLeave={() => isDragging.current = null}
>
<defs>
<pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse">
<path d="M 20 0 L 0 0 0 20" fill="none" stroke="#e2e8f0" strokeWidth="0.5"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid)" />
{/* Circle */}
<circle cx={center.x} cy={center.y} r={radius} fill="white" stroke="#94a3b8" strokeWidth="2" />
<circle cx={center.x} cy={center.y} r="3" fill="#cbd5e1" />
{mode === 'chords' ? renderChords() : renderSecant()}
</svg>
</div>
<div className="mt-4 text-center text-sm text-slate-500">
{mode === 'chords'
? "Drag the colored points along the circle."
: "Drag point P or the secant endpoint B."
}
</div>
</div>
);
};
export default PowerOfPointWidget;

View File

@ -0,0 +1,110 @@
import React, { useState } from 'react';
type HighlightMode = 'none' | 'bus' | 'club' | 'cond_club_bus' | 'cond_bus_club' | 'or_bus_club';
const ProbabilityTableWidget: React.FC = () => {
const [highlight, setHighlight] = useState<HighlightMode>('none');
const data = {
bus_club: 36, bus_noClub: 24,
noBus_club: 30, noBus_noClub: 30
};
const totals = {
bus: data.bus_club + data.bus_noClub, // 60
noBus: data.noBus_club + data.noBus_noClub, // 60
club: data.bus_club + data.noBus_club, // 66
noClub: data.bus_noClub + data.noBus_noClub, // 54
total: 120
};
const getCellClass = (cell: string) => {
const base = "p-4 text-center border font-mono font-bold transition-colors duration-300 ";
// Logic for highlighting based on mode
let isNum = false;
let isDenom = false;
if (highlight === 'bus') {
if (cell === 'bus_total') isNum = true;
if (cell === 'grand_total') isDenom = true;
} else if (highlight === 'club') {
if (cell === 'club_total') isNum = true;
if (cell === 'grand_total') isDenom = true;
} else if (highlight === 'cond_club_bus') {
if (cell === 'bus_club') isNum = true;
if (cell === 'bus_total') isDenom = true;
} else if (highlight === 'cond_bus_club') {
if (cell === 'bus_club') isNum = true;
if (cell === 'club_total') isDenom = true;
} else if (highlight === 'or_bus_club') {
if (['bus_club', 'bus_noClub', 'noBus_club'].includes(cell)) isNum = true;
if (cell === 'grand_total') isDenom = true;
}
if (isNum) return base + "bg-emerald-100 text-emerald-800 border-emerald-300";
if (isDenom) return base + "bg-indigo-100 text-indigo-800 border-indigo-300";
return base + "bg-white border-slate-200 text-slate-600";
};
const explanation = () => {
switch(highlight) {
case 'bus': return { title: "P(Bus)", math: `${totals.bus} / ${totals.total} = 0.50` };
case 'club': return { title: "P(Club)", math: `${totals.club} / ${totals.total} = 0.55` };
case 'cond_club_bus': return { title: "P(Club | Bus)", math: `${data.bus_club} / ${totals.bus} = 0.60`, sub: "Given Bus, restrict to Bus row." };
case 'cond_bus_club': return { title: "P(Bus | Club)", math: `${data.bus_club} / ${totals.club} ≈ 0.55`, sub: "Given Club, restrict to Club column." };
case 'or_bus_club': return { title: "P(Bus OR Club)", math: `(${totals.bus} + ${totals.club} - ${data.bus_club}) / ${totals.total} = ${totals.bus+totals.club-data.bus_club}/${totals.total} = 0.75`, sub: "Add totals, subtract overlap." };
default: return { title: "Select a Probability", math: "---" };
}
};
const exp = explanation();
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-wrap gap-2 mb-6 justify-center">
<button onClick={() => setHighlight('bus')} className="px-3 py-1 bg-slate-100 hover:bg-slate-200 rounded text-sm font-bold text-slate-700">P(Bus)</button>
<button onClick={() => setHighlight('club')} className="px-3 py-1 bg-slate-100 hover:bg-slate-200 rounded text-sm font-bold text-slate-700">P(Club)</button>
<button onClick={() => setHighlight('cond_club_bus')} className="px-3 py-1 bg-indigo-100 hover:bg-indigo-200 rounded text-sm font-bold text-indigo-700">P(Club | Bus)</button>
<button onClick={() => setHighlight('cond_bus_club')} className="px-3 py-1 bg-indigo-100 hover:bg-indigo-200 rounded text-sm font-bold text-indigo-700">P(Bus | Club)</button>
<button onClick={() => setHighlight('or_bus_club')} className="px-3 py-1 bg-emerald-100 hover:bg-emerald-200 rounded text-sm font-bold text-emerald-700">P(Bus OR Club)</button>
</div>
<div className="overflow-hidden rounded-lg border border-slate-200 mb-6">
<div className="grid grid-cols-4 bg-slate-50 border-b border-slate-200">
<div className="p-3 text-center text-xs font-bold text-slate-400 uppercase"></div>
<div className="p-3 text-center text-xs font-bold text-slate-500 uppercase">Club</div>
<div className="p-3 text-center text-xs font-bold text-slate-500 uppercase">No Club</div>
<div className="p-3 text-center text-xs font-bold text-slate-800 uppercase">Total</div>
</div>
<div className="grid grid-cols-4">
<div className="p-4 flex items-center justify-center font-bold text-slate-600 bg-slate-50 border-r border-slate-200">Bus</div>
<div className={getCellClass('bus_club')}>{data.bus_club}</div>
<div className={getCellClass('bus_noClub')}>{data.bus_noClub}</div>
<div className={getCellClass('bus_total')}>{totals.bus}</div>
<div className="p-4 flex items-center justify-center font-bold text-slate-600 bg-slate-50 border-r border-slate-200 border-t border-slate-200">No Bus</div>
<div className={getCellClass('noBus_club')}>{data.noBus_club}</div>
<div className={getCellClass('noBus_noClub')}>{data.noBus_noClub}</div>
<div className={getCellClass('noBus_total')}>{totals.noBus}</div>
<div className="p-4 flex items-center justify-center font-bold text-slate-900 bg-slate-100 border-r border-slate-200 border-t border-slate-200">Total</div>
<div className={getCellClass('club_total')}>{totals.club}</div>
<div className={getCellClass('noClub_total')}>{totals.noClub}</div>
<div className={getCellClass('grand_total')}>{totals.total}</div>
</div>
</div>
<div className="bg-slate-50 p-4 rounded-xl text-center">
<h4 className="text-sm font-bold text-slate-500 uppercase mb-2">{exp.title}</h4>
<div className="text-2xl font-mono font-bold text-slate-800 mb-1">
{exp.math}
</div>
{exp.sub && <p className="text-xs text-slate-400">{exp.sub}</p>}
</div>
</div>
);
};
export default ProbabilityTableWidget;

View File

@ -0,0 +1,253 @@
import React, { useState } from 'react';
const ProbabilityTreeWidget: React.FC = () => {
const [replacement, setReplacement] = useState(false);
const [initR, setInitR] = useState(3);
const [initB, setInitB] = useState(4);
const [hoverPath, setHoverPath] = useState<string | null>(null); // 'RR', 'RB', 'BR', 'BB'
const total = initR + initB;
// Level 1 Probs
const pR = initR / total;
const pB = initB / total;
// Level 2 Probs (Given R)
const r_R = replacement ? initR : Math.max(0, initR - 1);
const r_Total = replacement ? total : total - 1;
const pR_R = r_Total > 0 ? r_R / r_Total : 0;
const pB_R = r_Total > 0 ? 1 - pR_R : 0;
// Level 2 Probs (Given B)
const b_B = replacement ? initB : Math.max(0, initB - 1);
const b_Total = replacement ? total : total - 1;
const pB_B = b_Total > 0 ? b_B / b_Total : 0;
const pR_B = b_Total > 0 ? 1 - pB_B : 0;
// Final Probs
const pRR = pR * pR_R;
const pRB = pR * pB_R;
const pBR = pB * pR_B;
const pBB = pB * pB_B;
const fraction = (num: number, den: number) => {
if (den === 0) return "0";
return (
<span className="font-mono bg-white px-1 rounded shadow-sm border border-slate-200 text-xs inline-block mx-1">
{num}/{den}
</span>
);
};
const getPathColor = (path: string, segment: 'top' | 'bottom' | 'top-top' | 'top-bottom' | 'bottom-top' | 'bottom-bottom') => {
const defaultColor = "#cbd5e1"; // Slate 300
if (!hoverPath) {
// Default coloring based on branch type
if (segment.includes('top')) return "#f43f5e"; // Red branches
if (segment.includes('bottom')) return "#3b82f6"; // Blue branches
return defaultColor;
}
// Highlighting logic based on hoverPath
if (segment === 'top') return (hoverPath === 'RR' || hoverPath === 'RB') ? "#f43f5e" : "#f1f5f9";
if (segment === 'bottom') return (hoverPath === 'BR' || hoverPath === 'BB') ? "#3b82f6" : "#f1f5f9";
if (segment === 'top-top') return hoverPath === 'RR' ? "#f43f5e" : "#f1f5f9";
if (segment === 'top-bottom') return hoverPath === 'RB' ? "#3b82f6" : "#f1f5f9";
if (segment === 'bottom-top') return hoverPath === 'BR' ? "#f43f5e" : "#f1f5f9";
if (segment === 'bottom-bottom') return hoverPath === 'BB' ? "#3b82f6" : "#f1f5f9";
return defaultColor;
};
const getStrokeWidth = (segment: string) => {
if (!hoverPath) return 2;
if (segment === 'top') return (hoverPath === 'RR' || hoverPath === 'RB') ? 4 : 1;
if (segment === 'bottom') return (hoverPath === 'BR' || hoverPath === 'BB') ? 4 : 1;
if (segment === 'top-top') return hoverPath === 'RR' ? 4 : 1;
if (segment === 'top-bottom') return hoverPath === 'RB' ? 4 : 1;
if (segment === 'bottom-top') return hoverPath === 'BR' ? 4 : 1;
if (segment === 'bottom-bottom') return hoverPath === 'BB' ? 4 : 1;
return 2;
}
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
{/* Controls */}
<div className="flex flex-wrap justify-between items-center mb-6 gap-4">
<div className="flex gap-4">
<div className="flex flex-col">
<label className="text-xs font-bold text-rose-600 uppercase mb-1">Red Items</label>
<div className="flex items-center gap-2">
<button onClick={() => setInitR(Math.max(1, initR-1))} className="w-6 h-6 bg-rose-100 text-rose-700 rounded hover:bg-rose-200">-</button>
<span className="font-bold w-4 text-center">{initR}</span>
<button onClick={() => setInitR(Math.min(10, initR+1))} className="w-6 h-6 bg-rose-100 text-rose-700 rounded hover:bg-rose-200">+</button>
</div>
</div>
<div className="flex flex-col">
<label className="text-xs font-bold text-blue-600 uppercase mb-1">Blue Items</label>
<div className="flex items-center gap-2">
<button onClick={() => setInitB(Math.max(1, initB-1))} className="w-6 h-6 bg-blue-100 text-blue-700 rounded hover:bg-blue-200">-</button>
<span className="font-bold w-4 text-center">{initB}</span>
<button onClick={() => setInitB(Math.min(10, initB+1))} className="w-6 h-6 bg-blue-100 text-blue-700 rounded hover:bg-blue-200">+</button>
</div>
</div>
</div>
<div className="flex bg-slate-100 p-1 rounded-lg">
<button
onClick={() => setReplacement(true)}
className={`px-3 py-1 text-xs font-bold rounded transition-all ${replacement ? 'bg-white shadow text-indigo-600' : 'text-slate-500'}`}
>
With Replacement
</button>
<button
onClick={() => setReplacement(false)}
className={`px-3 py-1 text-xs font-bold rounded transition-all ${!replacement ? 'bg-white shadow text-indigo-600' : 'text-slate-500'}`}
>
Without Replacement
</button>
</div>
</div>
<div className="relative h-64 w-full max-w-lg mx-auto select-none">
<svg width="100%" height="100%" className="overflow-visible">
{/* Root */}
<circle cx="20" cy="128" r="6" fill="#64748b" />
{/* Level 1 Branches */}
<path d="M 20 128 C 50 128, 50 64, 150 64" fill="none" stroke={getPathColor('R', 'top')} strokeWidth={getStrokeWidth('top')} className="transition-all duration-300" />
<path d="M 20 128 C 50 128, 50 192, 150 192" fill="none" stroke={getPathColor('B', 'bottom')} strokeWidth={getStrokeWidth('bottom')} className="transition-all duration-300" />
{/* Level 1 Labels */}
<foreignObject x="60" y="70" width="60" height="30">
<div className={`text-center font-bold text-xs ${hoverPath && (hoverPath[0]!=='R') ? 'text-slate-300' : 'text-rose-600'}`}>{initR}/{total}</div>
</foreignObject>
<foreignObject x="60" y="150" width="60" height="30">
<div className={`text-center font-bold text-xs ${hoverPath && (hoverPath[0]!=='B') ? 'text-slate-300' : 'text-blue-600'}`}>{initB}/{total}</div>
</foreignObject>
{/* Level 1 Nodes */}
<circle cx="150" cy="64" r="18" fill="#f43f5e" className={`transition-all ${hoverPath && hoverPath[0] !== 'R' ? 'opacity-20' : 'opacity-100 shadow-md'}`} />
<text x="150" y="68" textAnchor="middle" fill="white" className={`text-xs font-bold pointer-events-none ${hoverPath && hoverPath[0] !== 'R' ? 'opacity-20' : ''}`}>R</text>
<circle cx="150" cy="192" r="18" fill="#3b82f6" className={`transition-all ${hoverPath && hoverPath[0] !== 'B' ? 'opacity-20' : 'opacity-100 shadow-md'}`} />
<text x="150" y="196" textAnchor="middle" fill="white" className={`text-xs font-bold pointer-events-none ${hoverPath && hoverPath[0] !== 'B' ? 'opacity-20' : ''}`}>B</text>
{/* Level 2 Branches (Top) */}
<path d="M 168 64 L 280 32" fill="none" stroke={getPathColor('RR', 'top-top')} strokeWidth={getStrokeWidth('top-top')} strokeDasharray="4,2" className="transition-all duration-300" />
<path d="M 168 64 L 280 96" fill="none" stroke={getPathColor('RB', 'top-bottom')} strokeWidth={getStrokeWidth('top-bottom')} strokeDasharray="4,2" className="transition-all duration-300" />
{/* Level 2 Top Labels */}
<foreignObject x="190" y="25" width="60" height="30">
<div className={`text-center font-bold text-xs ${hoverPath === 'RR' ? 'text-rose-600 scale-110' : 'text-slate-400'}`}>{r_R}/{r_Total}</div>
</foreignObject>
<foreignObject x="190" y="80" width="60" height="30">
<div className={`text-center font-bold text-xs ${hoverPath === 'RB' ? 'text-blue-600 scale-110' : 'text-slate-400'}`}>{initB}/{r_Total}</div>
</foreignObject>
{/* Level 2 Branches (Bottom) */}
<path d="M 168 192 L 280 160" fill="none" stroke={getPathColor('BR', 'bottom-top')} strokeWidth={getStrokeWidth('bottom-top')} strokeDasharray="4,2" className="transition-all duration-300" />
<path d="M 168 192 L 280 224" fill="none" stroke={getPathColor('BB', 'bottom-bottom')} strokeWidth={getStrokeWidth('bottom-bottom')} strokeDasharray="4,2" className="transition-all duration-300" />
{/* Level 2 Bottom Labels */}
<foreignObject x="190" y="150" width="60" height="30">
<div className={`text-center font-bold text-xs ${hoverPath === 'BR' ? 'text-rose-600 scale-110' : 'text-slate-400'}`}>{initR}/{b_Total}</div>
</foreignObject>
<foreignObject x="190" y="210" width="60" height="30">
<div className={`text-center font-bold text-xs ${hoverPath === 'BB' ? 'text-blue-600 scale-110' : 'text-slate-400'}`}>{b_B}/{b_Total}</div>
</foreignObject>
{/* Outcomes (Interactive Targets) */}
<g
className="cursor-pointer"
onMouseEnter={() => setHoverPath('RR')}
onMouseLeave={() => setHoverPath(null)}
>
<text x="300" y="36" className={`text-xs font-bold transition-all ${hoverPath === 'RR' ? 'fill-rose-600 text-base' : 'fill-slate-500'}`}>RR: {(pRR * 100).toFixed(1)}%</text>
<rect x="290" y="20" width="80" height="20" fill="transparent" />
</g>
<g
className="cursor-pointer"
onMouseEnter={() => setHoverPath('RB')}
onMouseLeave={() => setHoverPath(null)}
>
<text x="300" y="100" className={`text-xs font-bold transition-all ${hoverPath === 'RB' ? 'fill-indigo-600 text-base' : 'fill-slate-500'}`}>RB: {(pRB * 100).toFixed(1)}%</text>
<rect x="290" y="85" width="80" height="20" fill="transparent" />
</g>
<g
className="cursor-pointer"
onMouseEnter={() => setHoverPath('BR')}
onMouseLeave={() => setHoverPath(null)}
>
<text x="300" y="164" className={`text-xs font-bold transition-all ${hoverPath === 'BR' ? 'fill-indigo-600 text-base' : 'fill-slate-500'}`}>BR: {(pBR * 100).toFixed(1)}%</text>
<rect x="290" y="150" width="80" height="20" fill="transparent" />
</g>
<g
className="cursor-pointer"
onMouseEnter={() => setHoverPath('BB')}
onMouseLeave={() => setHoverPath(null)}
>
<text x="300" y="228" className={`text-xs font-bold transition-all ${hoverPath === 'BB' ? 'fill-blue-600 text-base' : 'fill-slate-500'}`}>BB: {(pBB * 100).toFixed(1)}%</text>
<rect x="290" y="215" width="80" height="20" fill="transparent" />
</g>
</svg>
</div>
{/* Calculation Panel */}
<div className={`p-4 rounded-lg border text-sm mt-4 transition-colors ${hoverPath ? 'bg-amber-50 border-amber-200 text-amber-900' : 'bg-slate-50 border-slate-100 text-slate-400'}`}>
{!hoverPath ? (
<p className="text-center italic">Hover over an outcome (e.g., RR) to see the calculation.</p>
) : (
<>
<p className="font-bold mb-1">
Calculation for <span className="font-mono bg-white px-1 rounded border border-amber-200">{hoverPath}</span>
({hoverPath[0] === 'R' ? 'Red' : 'Blue'} then {hoverPath[1] === 'R' ? 'Red' : 'Blue'}):
</p>
<div className="flex flex-wrap items-center gap-2 font-mono text-lg mt-2 justify-center sm:justify-start">
{/* First Draw */}
<span>P({hoverPath[0]})</span>
<span>×</span>
<span>P({hoverPath[1]} | {hoverPath[0]})</span>
<span>=</span>
{/* Numbers */}
{fraction(hoverPath[0] === 'R' ? initR : initB, total)}
<span>×</span>
{fraction(
hoverPath === 'RR' ? r_R : hoverPath === 'RB' ? initB : hoverPath === 'BR' ? initR : b_B,
hoverPath[0] === 'R' ? r_Total : b_Total
)}
<span>=</span>
{/* Result */}
<strong className="text-amber-700">
{fraction(
(hoverPath[0] === 'R' ? initR : initB) * (hoverPath === 'RR' ? r_R : hoverPath === 'RB' ? initB : hoverPath === 'BR' ? initR : b_B),
total * (hoverPath[0] === 'R' ? r_Total : b_Total)
)}
</strong>
</div>
{!replacement && hoverPath[0] === hoverPath[1] && (
<p className="text-xs mt-3 text-rose-600 font-bold bg-white p-2 rounded inline-block border border-rose-100">
Notice: The numerator decreased because we kept the first {hoverPath[0] === 'R' ? 'Red' : 'Blue'} item!
</p>
)}
</>
)}
</div>
</div>
);
};
export default ProbabilityTreeWidget;

View File

@ -0,0 +1,150 @@
import React, { useState } from "react";
import { type QuizData } from "../../types/lesson";
import { CheckCircle2, XCircle, ChevronRight } from "lucide-react";
interface QuizProps {
data: QuizData;
onComplete?: () => void;
}
const Quiz: React.FC<QuizProps> = ({ data, onComplete }) => {
const [selectedId, setSelectedId] = useState<string | null>(null);
const [isSubmitted, setIsSubmitted] = useState(false);
const handleOptionClick = (id: string) => {
if (isSubmitted && selectedId === id) return; // Allow changing selection if not correct? No, lock after submit usually. Let's strictly lock.
if (!isSubmitted) {
setSelectedId(id);
}
};
const handleSubmit = () => {
if (!selectedId) return;
setIsSubmitted(true);
const selectedOption = data.options.find((opt) => opt.id === selectedId);
if (selectedOption?.isCorrect && onComplete) {
onComplete();
}
};
const selectedOption = data.options.find((opt) => opt.id === selectedId);
const isCorrect = selectedOption?.isCorrect;
return (
<div className="w-full max-w-2xl mx-auto bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden mt-6">
<div className="p-6">
<h4 className="text-sm font-bold text-slate-400 uppercase tracking-wider mb-2">
Concept Check
</h4>
<p className="text-lg font-medium text-slate-900 mb-6 whitespace-pre-line">
{data.question}
</p>
<div className="space-y-3">
{data.options.map((option) => {
let borderClass = "border-slate-200 hover:border-indigo-300";
let bgClass = "bg-white hover:bg-slate-50";
let icon = null;
if (isSubmitted) {
if (option.id === selectedId) {
if (option.isCorrect) {
borderClass = "border-green-500 bg-green-50";
icon = <CheckCircle2 className="w-5 h-5 text-green-600" />;
} else {
borderClass = "border-red-500 bg-red-50";
icon = <XCircle className="w-5 h-5 text-red-600" />;
}
} else if (option.isCorrect) {
// Highlight correct answer if wrong one was picked
borderClass = "border-green-200 bg-green-50/50";
}
} else if (selectedId === option.id) {
borderClass = "border-indigo-600 bg-indigo-50";
}
return (
<button
key={option.id}
onClick={() => handleOptionClick(option.id)}
disabled={isSubmitted}
className={`w-full text-left p-4 rounded-lg border-2 transition-all duration-200 flex items-center justify-between group ${borderClass} ${bgClass}`}
>
<div className="flex items-center">
<span
className={`w-6 h-6 flex items-center justify-center rounded-full text-xs font-bold mr-3 ${
isSubmitted && option.isCorrect
? "bg-green-200 text-green-800"
: isSubmitted && option.id === selectedId
? "bg-red-200 text-red-800"
: selectedId === option.id
? "bg-indigo-600 text-white"
: "bg-slate-100 text-slate-500"
}`}
>
{option.id}
</span>
<span className="text-slate-700 group-hover:text-slate-900">
{option.text}
</span>
</div>
{icon}
</button>
);
})}
</div>
</div>
{/* Feedback Section */}
{isSubmitted && (
<div
className={`p-6 border-t ${isCorrect ? "bg-green-50 border-green-100" : "bg-slate-50 border-slate-100"}`}
>
<div className="flex items-start gap-3">
<div
className={`mt-1 p-1 rounded-full ${isCorrect ? "bg-green-200" : "bg-slate-200"}`}
>
{isCorrect ? (
<CheckCircle2 className="w-4 h-4 text-green-700" />
) : (
<div className="w-4 h-4 text-slate-500 font-bold text-center leading-4">
i
</div>
)}
</div>
<div>
<p
className={`font-bold ${isCorrect ? "text-green-800" : "text-slate-800"} mb-1`}
>
{isCorrect ? "That's right!" : "Not quite."}
</p>
<p className="text-slate-600 mb-2">{selectedOption?.feedback}</p>
<div className="text-sm text-slate-500 bg-white p-3 rounded border border-slate-200">
<span className="font-semibold block mb-1">Explanation:</span>
{data.explanation}
</div>
</div>
</div>
</div>
)}
{!isSubmitted && (
<div className="p-4 bg-slate-50 border-t border-slate-100 flex justify-end">
<button
onClick={handleSubmit}
disabled={!selectedId}
className={`px-6 py-2 rounded-full font-semibold transition-all flex items-center ${
selectedId
? "bg-slate-900 text-white hover:bg-slate-800 shadow-md transform hover:-translate-y-0.5"
: "bg-slate-200 text-slate-400 cursor-not-allowed"
}`}
>
Check Answer <ChevronRight className="w-4 h-4 ml-1" />
</button>
</div>
)}
</div>
);
};
export default Quiz;

View File

@ -0,0 +1,135 @@
import React, { useState } from 'react';
const RadicalSolutionWidget: React.FC = () => {
// Equation: sqrt(x) = x - k
const [k, setK] = useState(2);
// Intersection logic
// x = (x-k)^2 => x = x^2 - 2kx + k^2 => x^2 - (2k+1)x + k^2 = 0
// Roots via quadratic formula
const a = 1;
const b = -(2*k + 1);
const c = k*k;
const disc = b*b - 4*a*c;
let solutions: number[] = [];
if (disc >= 0) {
const x1 = (-b + Math.sqrt(disc)) / (2*a);
const x2 = (-b - Math.sqrt(disc)) / (2*a);
solutions = [x1, x2].filter(val => val >= 0); // Domain x>=0
}
// Check validity against original equation sqrt(x) = x - k
const validSolutions = solutions.filter(x => Math.abs(Math.sqrt(x) - (x - k)) < 0.01);
const extraneousSolutions = solutions.filter(x => Math.abs(Math.sqrt(x) - (x - k)) >= 0.01);
// Vis
const width = 300;
const height = 300;
const range = 10;
const scale = 25;
const toPx = (v: number, isY = false) => isY ? height - v * scale - 20 : v * scale + 20;
const pathSqrt = () => {
let d = "";
for(let x=0; x<=range; x+=0.1) {
d += d ? ` L ${toPx(x)} ${toPx(Math.sqrt(x), true)}` : `M ${toPx(x)} ${toPx(Math.sqrt(x), true)}`;
}
return d;
};
const pathLine = () => {
// y = x - k
const x1 = 0; const y1 = -k;
const x2 = range; const y2 = range - k;
return `M ${toPx(x1)} ${toPx(y1, true)} L ${toPx(x2)} ${toPx(y2, true)}`;
};
// Phantom parabola path (x = y^2) - representing the squared equation
// This includes y = -sqrt(x)
const pathPhantom = () => {
let d = "";
for(let x=0; x<=range; x+=0.1) {
d += d ? ` L ${toPx(x)} ${toPx(-Math.sqrt(x), true)}` : `M ${toPx(x)} ${toPx(-Math.sqrt(x), true)}`;
}
return d;
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8">
<div className="w-full md:w-1/3 space-y-6">
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200">
<div className="text-xs font-bold text-slate-400 uppercase mb-2">Equation</div>
<div className="font-mono text-lg font-bold text-slate-800">
x = x - {k}
</div>
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase">Shift Line (k) = {k}</label>
<input type="range" min="0" max="6" step="0.5" value={k} onChange={e => setK(parseFloat(e.target.value))} className="w-full h-2 bg-slate-200 rounded-lg accent-indigo-600 mt-2"/>
</div>
<div className="space-y-3">
<div className="p-3 bg-emerald-50 rounded border border-emerald-100">
<div className="text-xs font-bold text-emerald-700 uppercase mb-1">Valid Solutions</div>
<div className="font-mono text-sm font-bold text-emerald-900">
{validSolutions.length > 0 ? validSolutions.map(n => `x = ${n.toFixed(2)}`).join(', ') : "None"}
</div>
</div>
<div className="p-3 bg-rose-50 rounded border border-rose-100">
<div className="text-xs font-bold text-rose-700 uppercase mb-1">Extraneous Solutions</div>
<div className="font-mono text-sm font-bold text-rose-900">
{extraneousSolutions.length > 0 ? extraneousSolutions.map(n => `x = ${n.toFixed(2)}`).join(', ') : "None"}
</div>
</div>
</div>
<p className="text-xs text-slate-400 leading-relaxed">
The <span className="text-rose-400 font-bold">extraneous</span> solution is a real intersection for the <em>squared</em> equation (the phantom curve), but not for the original radical.
</p>
</div>
<div className="flex-1 flex justify-center">
<div className="relative w-[300px] h-[300px] bg-white border border-slate-200 rounded-xl overflow-hidden">
<svg width="100%" height="100%" viewBox="0 0 300 300">
{/* Grid */}
<defs>
<pattern id="grid-rad" width="25" height="25" patternUnits="userSpaceOnUse">
<path d="M 25 0 L 0 0 0 25" fill="none" stroke="#f8fafc" strokeWidth="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid-rad)" />
{/* Axes */}
<line x1="20" y1="0" x2="20" y2="300" stroke="#cbd5e1" strokeWidth="2" />
<line x1="0" y1={toPx(0, true)} x2="300" y2={toPx(0, true)} stroke="#cbd5e1" strokeWidth="2" />
{/* Phantom -sqrt(x) */}
<path d={pathPhantom()} fill="none" stroke="#cbd5e1" strokeWidth="2" strokeDasharray="4,4" />
{/* Real sqrt(x) */}
<path d={pathSqrt()} fill="none" stroke="#4f46e5" strokeWidth="3" />
{/* Line x-k */}
<path d={pathLine()} fill="none" stroke="#64748b" strokeWidth="2" />
{/* Points */}
{validSolutions.map(x => (
<circle key={`v-${x}`} cx={toPx(x)} cy={toPx(Math.sqrt(x), true)} r="5" fill="#10b981" stroke="white" strokeWidth="2" />
))}
{extraneousSolutions.map(x => (
<circle key={`e-${x}`} cx={toPx(x)} cy={toPx(-(Math.sqrt(x)), true)} r="5" fill="#f43f5e" stroke="white" strokeWidth="2" />
))}
</svg>
<div className="absolute top-2 right-2 text-xs font-bold text-indigo-600">y = x</div>
<div className="absolute bottom-10 right-2 text-xs font-bold text-slate-500">y = x - {k}</div>
</div>
</div>
</div>
</div>
);
};
export default RadicalSolutionWidget;

View File

@ -0,0 +1,71 @@
import React, { useState } from 'react';
const RadicalWidget: React.FC = () => {
const [power, setPower] = useState(3);
const [root, setRoot] = useState(2);
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 items-center mb-8">
<div className="space-y-6">
<div>
<label className="text-xs font-bold text-violet-600 uppercase mb-1 block">Power (Numerator) m</label>
<div className="flex items-center gap-4">
<input
type="range" min="1" max="9" value={power} onChange={e => setPower(parseInt(e.target.value))}
className="flex-1 h-2 bg-violet-100 rounded-lg accent-violet-600"
/>
<span className="font-mono font-bold text-violet-800 text-xl">{power}</span>
</div>
</div>
<div>
<label className="text-xs font-bold text-fuchsia-600 uppercase mb-1 block">Root (Denominator) n</label>
<div className="flex items-center gap-4">
<input
type="range" min="2" max="9" value={root} onChange={e => setRoot(parseInt(e.target.value))}
className="flex-1 h-2 bg-fuchsia-100 rounded-lg accent-fuchsia-600"
/>
<span className="font-mono font-bold text-fuchsia-800 text-xl">{root}</span>
</div>
</div>
</div>
<div className="flex flex-col items-center justify-center p-6 bg-slate-50 rounded-xl border border-slate-200 min-h-[160px]">
<div className="flex items-center gap-8 text-4xl font-serif">
{/* Rational Exponent Form */}
<div className="text-center group">
<span className="font-bold text-slate-700 italic">x</span>
<sup className="text-2xl font-sans font-bold">
<span className="text-violet-600 group-hover:scale-110 inline-block transition-transform">{power}</span>
<span className="text-slate-400 mx-1">/</span>
<span className="text-fuchsia-600 group-hover:scale-110 inline-block transition-transform">{root}</span>
</sup>
</div>
<span className="text-slate-300">=</span>
{/* Radical Form */}
<div className="text-center relative group">
<span className="absolute -top-3 -left-3 text-lg font-bold text-fuchsia-600 font-sans group-hover:scale-110 transition-transform">{root}</span>
<span className="text-slate-400"></span>
<span className="border-t-2 border-slate-400 px-1 font-bold text-slate-700 italic">
x
<sup className="text-violet-600 text-2xl font-sans ml-0.5 group-hover:scale-110 inline-block transition-transform">{power}</sup>
</span>
</div>
</div>
</div>
</div>
<div className="text-sm text-slate-600 bg-indigo-50 p-4 rounded-lg border border-indigo-100">
<p className="mb-2"><strong>The Golden Rule:</strong> The top number stays with x (power), the bottom number becomes the root.</p>
<p className="font-mono">
Exponent <span className="text-violet-600 font-bold">{power}</span> goes inside.
Root <span className="text-fuchsia-600 font-bold">{root}</span> goes outside.
</p>
</div>
</div>
);
};
export default RadicalWidget;

View File

@ -0,0 +1,80 @@
import React, { useState } from 'react';
const RatioVisualizerWidget: React.FC = () => {
const [partA, setPartA] = useState(3);
const [partB, setPartB] = useState(2);
const [scale, setScale] = useState(1);
const totalParts = partA + partB;
const scaledA = partA * scale;
const scaledB = partB * scale;
const scaledTotal = totalParts * scale;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8 mb-8">
<div className="w-full md:w-1/3 space-y-6">
<div>
<label className="text-xs font-bold text-indigo-600 uppercase">Part A (Indigo)</label>
<input
type="range" min="1" max="10" value={partA}
onChange={e => setPartA(parseInt(e.target.value))}
className="w-full h-2 bg-indigo-100 rounded-lg appearance-none cursor-pointer accent-indigo-600 mt-2"
/>
<div className="text-right font-mono font-bold text-indigo-700">{partA} parts</div>
</div>
<div>
<label className="text-xs font-bold text-rose-600 uppercase">Part B (Rose)</label>
<input
type="range" min="1" max="10" value={partB}
onChange={e => setPartB(parseInt(e.target.value))}
className="w-full h-2 bg-rose-100 rounded-lg appearance-none cursor-pointer accent-rose-600 mt-2"
/>
<div className="text-right font-mono font-bold text-rose-700">{partB} parts</div>
</div>
<div className="pt-4 border-t border-slate-200">
<label className="text-xs font-bold text-slate-500 uppercase">Multiplier (k)</label>
<input
type="range" min="1" max="5" value={scale}
onChange={e => setScale(parseInt(e.target.value))}
className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-slate-600 mt-2"
/>
<div className="text-right font-mono font-bold text-slate-700">k = {scale}</div>
</div>
</div>
<div className="flex-1 flex flex-col justify-center">
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200 mb-4">
<div className="flex flex-wrap gap-2 justify-center content-start min-h-[100px]">
{Array.from({ length: scaledA }).map((_, i) => (
<div key={`a-${i}`} className="w-6 h-6 rounded-full bg-indigo-500 shadow-sm animate-fade-in"></div>
))}
{Array.from({ length: scaledB }).map((_, i) => (
<div key={`b-${i}`} className="w-6 h-6 rounded-full bg-rose-500 shadow-sm animate-fade-in"></div>
))}
</div>
</div>
<div className="grid grid-cols-2 gap-4 text-center">
<div className="p-3 bg-white border border-slate-200 rounded-lg shadow-sm">
<p className="text-xs font-bold text-slate-400 uppercase">Part-to-Part Ratio</p>
<p className="text-lg font-bold text-slate-800">
<span className="text-indigo-600">{scaledA}</span> : <span className="text-rose-600">{scaledB}</span>
</p>
<p className="text-xs text-slate-400 mt-1">({partA}k : {partB}k)</p>
</div>
<div className="p-3 bg-white border border-slate-200 rounded-lg shadow-sm">
<p className="text-xs font-bold text-slate-400 uppercase">Part-to-Whole (Indigo)</p>
<p className="text-lg font-bold text-slate-800">
<span className="text-indigo-600">{scaledA}</span> / {scaledTotal}
</p>
<p className="text-xs text-slate-400 mt-1">({partA}k / {totalParts}k)</p>
</div>
</div>
</div>
</div>
</div>
);
};
export default RatioVisualizerWidget;

View File

@ -0,0 +1,109 @@
import React, { useState } from 'react';
const RationalExplorer: React.FC = () => {
const [cancelFactor, setCancelFactor] = useState(false); // If true, (x-2) is in numerator
// Base function f(x) = (x+1) / [(x-2)(x+1)] ? No simple case.
// Let's do: f(x) = (x+1) * [ (x-2) if cancel ] / [ (x-2) * (x-3) ]
// If cancel: f(x) = (x+1)/(x-3) with Hole at 2.
// If not cancel: f(x) = (x+1) / [(x-2)(x-3)] ... complex.
// Better example: f(x) = [numerator] / (x-2)
// Numerator options: (x-2) -> Hole. 1 -> VA.
const width = 300;
const height = 200;
const range = 6;
const scale = width / (range * 2);
const center = width / 2;
const toPx = (v: number, isY = false) => isY ? height/2 - v * scale : center + v * scale;
const generatePath = () => {
let d = "";
for (let x = -range; x <= range; x += 0.05) {
if (Math.abs(x - 2) < 0.1) continue; // Skip near discontinuity
let y = 0;
if (cancelFactor) {
// f(x) = (x-2) / (x-2) = 1
y = 1;
} else {
// f(x) = 1 / (x-2)
y = 1 / (x - 2);
}
if (Math.abs(y) > range) {
d += ` M `; // Break path
continue;
}
const px = toPx(x);
const py = toPx(y, true);
d += d.endsWith('M ') ? `${px} ${py}` : ` L ${px} ${py}`;
}
return d;
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="mb-6 flex flex-col items-center">
<div className="text-xl font-mono font-bold bg-slate-50 px-6 py-3 rounded-lg border border-slate-200 mb-4">
f(x) = <div className="inline-block align-middle text-center mx-2">
<div className="border-b border-slate-800 pb-1 mb-1">{cancelFactor ? <span className="text-rose-600">(x-2)</span> : "1"}</div>
<div className="text-indigo-600">(x-2)</div>
</div>
</div>
<div className="flex bg-slate-100 p-1 rounded-lg">
<button
onClick={() => setCancelFactor(false)}
className={`px-4 py-2 text-sm font-bold rounded-md transition-all ${!cancelFactor ? 'bg-white shadow text-slate-800' : 'text-slate-500'}`}
>
Different Factor (1)
</button>
<button
onClick={() => setCancelFactor(true)}
className={`px-4 py-2 text-sm font-bold rounded-md transition-all ${cancelFactor ? 'bg-white shadow text-slate-800' : 'text-slate-500'}`}
>
Common Factor (x-2)
</button>
</div>
</div>
<div className="relative h-[200px] w-full bg-white border border-slate-200 rounded-xl overflow-hidden">
<svg width="100%" height="100%" viewBox={`0 0 ${width} ${height}`}>
{/* Axes */}
<line x1="0" y1={height/2} x2={width} y2={height/2} stroke="#cbd5e1" strokeWidth="2" />
<line x1={center} y1="0" x2={center} y2={height} stroke="#cbd5e1" strokeWidth="2" />
{/* Discontinuity at x=2 */}
<line x1={toPx(2)} y1={0} x2={toPx(2)} y2={height} stroke="#cbd5e1" strokeDasharray="4,4" />
{/* Graph */}
<path d={generatePath()} stroke="#8b5cf6" strokeWidth="3" fill="none" />
{/* Hole Visualization */}
{cancelFactor && (
<circle cx={toPx(2)} cy={toPx(1, true)} r="4" fill="white" stroke="#8b5cf6" strokeWidth="2" />
)}
</svg>
{/* Labels */}
<div className="absolute top-2 right-2 text-xs font-bold text-slate-400">x=2</div>
</div>
<div className="mt-4 p-4 rounded-lg bg-violet-50 border border-violet-100 text-sm text-violet-900 text-center">
{cancelFactor ? (
<span>
<strong>Hole:</strong> The factor (x-2) cancels out. The graph looks like y=1, but x=2 is undefined.
</span>
) : (
<span>
<strong>Vertical Asymptote:</strong> The factor (x-2) stays in the denominator. y approaches infinity near x=2.
</span>
)}
</div>
</div>
);
};
export default RationalExplorer;

View File

@ -0,0 +1,86 @@
import React, { useState } from 'react';
const RemainderTheoremWidget: React.FC = () => {
const [a, setA] = useState(2); // Dividing by (x - a)
// Polynomial P(x) = x^3 - 3x^2 - x + 3
const calculateP = (x: number) => Math.pow(x, 3) - 3 * Math.pow(x, 2) - x + 3;
const remainder = calculateP(a);
// Visualization
const width = 300;
const height = 200;
const rangeX = 4;
const rangeY = 10;
const scaleX = width / (rangeX * 2);
const scaleY = height / (rangeY * 2);
const centerX = width / 2;
const centerY = height / 2;
const toPx = (x: number, y: number) => ({
x: centerX + x * scaleX,
y: centerY - y * scaleY
});
const path = [];
for(let x = -rangeX; x <= rangeX; x+=0.1) {
const y = calculateP(x);
if(Math.abs(y) <= rangeY) {
path.push(toPx(x, y));
}
}
const pathD = `M ${path.map(p => `${p.x} ${p.y}`).join(' L ')}`;
const point = toPx(a, remainder);
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8 items-center">
<div className="flex-1 space-y-4">
<div className="p-4 bg-violet-50 rounded-xl border border-violet-100">
<p className="text-xs font-bold text-violet-400 uppercase mb-1">Polynomial</p>
<p className="font-mono font-bold text-lg text-slate-700">P(x) = x³ - 3x² - x + 3</p>
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase">Divisor (x - a)</label>
<div className="flex items-center gap-4 mt-1">
<span className="font-mono font-bold text-lg text-slate-700">x - </span>
<input
type="number" value={a} onChange={e => setA(parseFloat(e.target.value))}
className="w-16 p-2 border rounded text-center font-bold text-indigo-600"
/>
</div>
<input
type="range" min="-3" max="4" step="0.1" value={a}
onChange={e => setA(parseFloat(e.target.value))}
className="w-full mt-2 h-2 bg-slate-200 rounded-lg accent-indigo-600"
/>
</div>
<div className="p-4 bg-emerald-50 rounded-xl border border-emerald-100">
<p className="text-xs font-bold text-emerald-600 uppercase mb-1">Remainder Theorem Result</p>
<p className="text-sm text-slate-600 mb-2">Remainder of P(x) ÷ (x - {a}) is <strong>P({a})</strong></p>
<p className="font-mono font-bold text-2xl text-emerald-700">
R = {remainder.toFixed(2)}
</p>
</div>
</div>
<div className="flex-none">
<div className="relative w-[300px] h-[200px] border border-slate-200 rounded-xl bg-white overflow-hidden">
<svg width="100%" height="100%" viewBox="0 0 300 200">
<line x1="0" y1={centerY} x2={width} y2={centerY} stroke="#e2e8f0" strokeWidth="2" />
<line x1={centerX} y1="0" x2={centerX} y2={height} stroke="#e2e8f0" strokeWidth="2" />
<path d={pathD} fill="none" stroke="#8b5cf6" strokeWidth="3" />
<circle cx={point.x} cy={point.y} r="6" fill="#10b981" stroke="white" strokeWidth="2" />
<text x={point.x + 10} y={point.y} className="text-xs font-bold fill-slate-500">({a}, {remainder.toFixed(1)})</text>
</svg>
</div>
</div>
</div>
</div>
);
};
export default RemainderTheoremWidget;

View File

@ -0,0 +1,166 @@
import React, { useState, useEffect } from 'react';
import { RefreshCw } from 'lucide-react';
interface Dot {
id: number;
type: 'red' | 'blue';
x: number;
y: number;
}
const SamplingVisualizerWidget: React.FC = () => {
const [population, setPopulation] = useState<Dot[]>([]);
const [sample, setSample] = useState<number[]>([]); // IDs of selected dots
const [mode, setMode] = useState<'none' | 'random' | 'biased'>('none');
// Generate population on mount
useEffect(() => {
const dots: Dot[] = [];
for (let i = 0; i < 100; i++) {
// Biased distribution: Reds cluster in top-right
const isClustered = i < 40; // 40% Red
let x, y;
if (isClustered) {
// Cluster Reds (Type A) in top right (50-100, 0-50)
x = 50 + Math.random() * 50;
y = Math.random() * 50;
} else {
// Blues scattered everywhere else, but mostly bottom/left
// To make it simple, just uniform random, but if we hit the "Red Zone" we retry or accept overlap
// Let's force Blues to be mostly Bottom or Left
if (Math.random() > 0.5) {
x = Math.random() * 50; // Left half
y = Math.random() * 100;
} else {
x = 50 + Math.random() * 50; // Right half
y = 50 + Math.random() * 50; // Bottom right
}
}
dots.push({
id: i,
type: isClustered ? 'red' : 'blue',
x,
y
});
}
setPopulation(dots);
}, []);
const takeRandomSample = () => {
const indices: number[] = [];
const pool = [...population];
// Pick 10 random
for (let i = 0; i < 10; i++) {
const idx = Math.floor(Math.random() * pool.length);
indices.push(pool[idx].id);
pool.splice(idx, 1);
}
setSample(indices);
setMode('random');
};
const takeBiasedSample = () => {
// Simulate "Convenience": Pick from top-right (the Red cluster)
// Find dots with x > 50 and y < 50
const candidates = population.filter(d => d.x > 50 && d.y < 50);
// Take 10 from there
const selected = candidates.slice(0, 10).map(d => d.id);
setSample(selected);
setMode('biased');
};
// Stats
const sampleDots = population.filter(d => sample.includes(d.id));
const sampleRedCount = sampleDots.filter(d => d.type === 'red').length;
const samplePercent = sampleDots.length > 0 ? (sampleRedCount / sampleDots.length) * 100 : 0;
const truePercent = 40; // Hardcoded based on generation logic
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8">
<div className="flex-1">
<div className="relative h-64 bg-slate-50 rounded-lg border border-slate-200 overflow-hidden mb-4">
{population.map(dot => {
const isSelected = sample.includes(dot.id);
const isRed = dot.type === 'red';
return (
<div
key={dot.id}
className={`absolute w-3 h-3 rounded-full transition-all duration-500 ${
isSelected
? 'ring-4 ring-offset-1 z-10 scale-125'
: 'opacity-40 scale-75'
} ${
isRed ? 'bg-rose-500' : 'bg-indigo-500'
} ${
isSelected && isRed ? 'ring-rose-200' : ''
} ${
isSelected && !isRed ? 'ring-indigo-200' : ''
}`}
style={{ left: `${dot.x}%`, top: `${dot.y}%` }}
/>
);
})}
{/* Labels for Bias Zone */}
<div className="absolute top-2 right-2 text-xs font-bold text-rose-300 uppercase pointer-events-none">
Cluster Zone
</div>
</div>
<p className="text-xs text-center text-slate-400">Population: 100 individuals (40% Red)</p>
</div>
<div className="w-full md:w-1/3 flex flex-col justify-center space-y-4">
<div className="space-y-2">
<button
onClick={takeRandomSample}
className="w-full py-3 px-4 bg-emerald-100 hover:bg-emerald-200 text-emerald-800 rounded-lg font-bold transition-colors flex items-center justify-center gap-2"
>
<RefreshCw className="w-4 h-4" /> Random Sample
</button>
<button
onClick={takeBiasedSample}
className="w-full py-3 px-4 bg-amber-100 hover:bg-amber-200 text-amber-800 rounded-lg font-bold transition-colors"
>
Convenience Sample
</button>
</div>
<div className={`p-4 rounded-xl border ${mode === 'none' ? 'border-slate-100 bg-slate-50' : 'bg-white border-slate-200'}`}>
<h4 className="text-xs font-bold text-slate-400 uppercase mb-2">Sample Result (n=10)</h4>
{mode === 'none' ? (
<p className="text-sm text-slate-500 italic">Select a method...</p>
) : (
<div>
<div className="flex justify-between items-end mb-1">
<span className="text-slate-600 font-medium">Estimated Red %</span>
<span className={`text-2xl font-bold ${Math.abs(samplePercent - truePercent) > 15 ? 'text-rose-600' : 'text-emerald-600'}`}>
{samplePercent}%
</span>
</div>
<div className="w-full bg-slate-100 rounded-full h-2 mb-2">
<div
className={`h-2 rounded-full transition-all duration-500 ${Math.abs(samplePercent - truePercent) > 15 ? 'bg-rose-500' : 'bg-emerald-500'}`}
style={{ width: `${samplePercent}%` }}
></div>
</div>
<p className="text-xs text-slate-400 text-right">True Population: 40%</p>
{mode === 'biased' && (
<p className="mt-2 text-xs font-bold text-amber-600 bg-amber-50 p-2 rounded">
Bias Alert: Selecting only from the "easy to reach" cluster overestimates the Red group.
</p>
)}
</div>
)}
</div>
</div>
</div>
</div>
);
};
export default SamplingVisualizerWidget;

View File

@ -0,0 +1,133 @@
import React, { useState } from "react";
const ScaleFactorWidget: React.FC = () => {
const [k, setK] = useState(2);
const unit = 24; // Base size in px
const size = k * unit;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200 w-full max-w-3xl">
<div className="mb-8">
<label className="flex justify-between font-bold text-slate-700 mb-2">
Scale Factor (k):{" "}
<span className="text-indigo-600 text-xl">{k}x</span>
</label>
<input
type="range"
min="1"
max="4"
step="1"
value={k}
onChange={(e) => setK(parseInt(e.target.value))}
className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-indigo-600"
/>
<div className="flex justify-between text-xs text-slate-400 mt-1 font-mono">
<span>1x</span>
<span>2x</span>
<span>3x</span>
<span>4x</span>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 text-center">
{/* 1D: Length */}
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200 flex flex-col">
<h4 className="text-sm font-bold uppercase text-slate-500 mb-4">
1D: Length
</h4>
<div className="flex-1 flex items-center justify-center min-h-[160px]">
<div
className="h-3 bg-indigo-500 rounded-full transition-all duration-500 shadow-sm"
style={{ width: `${k * 20}%` }}
></div>
</div>
<div className="mt-auto border-t border-slate-200 pt-2">
<p className="text-slate-500 text-xs">Multiplier</p>
<p className="text-2xl font-bold text-indigo-700">k = {k}</p>
</div>
</div>
{/* 2D: Area */}
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200 flex flex-col">
<h4 className="text-sm font-bold uppercase text-slate-500 mb-4">
2D: Area
</h4>
<div className="flex-1 flex items-center justify-center relative min-h-[160px]">
{/* Base */}
<div className="w-8 h-8 border-2 border-emerald-500/30 absolute"></div>
{/* Scaled */}
<div
className="bg-emerald-500 shadow-lg transition-all duration-500 ease-out"
style={{ width: `${size}px`, height: `${size}px` }}
></div>
</div>
<div className="mt-auto border-t border-slate-200 pt-2">
<p className="text-slate-500 text-xs">Multiplier</p>
<p className="text-2xl font-bold text-emerald-700">k² = {k * k}</p>
</div>
</div>
{/* 3D: Volume */}
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200 flex flex-col overflow-hidden">
<h4 className="text-sm font-bold uppercase text-slate-500 mb-4">
3D: Volume
</h4>
<div className="flex-1 flex items-center justify-center perspective-1000 min-h-[160px]">
<div
className="relative transform-style-3d transition-all duration-500 ease-out"
style={{
width: `${size}px`,
height: `${size}px`,
transform: "rotateX(-20deg) rotateY(-30deg)",
}}
>
{/* Faces */}
{[
// Front
{ trans: `translateZ(${size / 2}px)`, color: "bg-rose-500" },
// Back
{
trans: `rotateY(180deg) translateZ(${size / 2}px)`,
color: "bg-rose-600",
},
// Right
{
trans: `rotateY(90deg) translateZ(${size / 2}px)`,
color: "bg-rose-600",
},
// Left
{
trans: `rotateY(-90deg) translateZ(${size / 2}px)`,
color: "bg-rose-500",
},
// Top
{
trans: `rotateX(90deg) translateZ(${size / 2}px)`,
color: "bg-rose-400",
},
// Bottom
{
trans: `rotateX(-90deg) translateZ(${size / 2}px)`,
color: "bg-rose-700",
},
].map((face, i) => (
<div
key={i}
className={`absolute inset-0 border border-white/20 ${face.color} shadow-sm`}
style={{ transform: face.trans }}
/>
))}
</div>
</div>
<div className="mt-auto border-t border-slate-200 pt-2">
<p className="text-slate-500 text-xs">Multiplier</p>
<p className="text-2xl font-bold text-rose-700">k³ = {k * k * k}</p>
</div>
</div>
</div>
</div>
);
};
export default ScaleFactorWidget;

View File

@ -0,0 +1,125 @@
import React, { useState } from 'react';
interface DataPoint {
x: number;
y: number;
isOutlier?: boolean;
}
const ScatterplotInteractiveWidget: React.FC = () => {
const [showLine, setShowLine] = useState(false);
const [showResiduals, setShowResiduals] = useState(false);
const [hasOutlier, setHasOutlier] = useState(false);
// Base Data (approx linear y = 1.5x + 10)
const basePoints: DataPoint[] = [
{x: 1, y: 12}, {x: 2, y: 14}, {x: 3, y: 13}, {x: 4, y: 17},
{x: 5, y: 18}, {x: 6, y: 19}, {x: 7, y: 22}, {x: 8, y: 21}
];
const points: DataPoint[] = hasOutlier
? [...basePoints, {x: 7, y: 5, isOutlier: true}]
: basePoints;
// Simple Linear Regression Calculation
const n = points.length;
const sumX = points.reduce((a, p) => a + p.x, 0);
const sumY = points.reduce((a, p) => a + p.y, 0);
const sumXY = points.reduce((a, p) => a + p.x * p.y, 0);
const sumXX = points.reduce((a, p) => a + p.x * p.x, 0);
const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);
const intercept = (sumY - slope * sumX) / n;
const predict = (x: number) => slope * x + intercept;
// Scales
const width = 400;
const height = 250;
const maxX = 9;
const maxY = 25;
const toX = (val: number) => (val / maxX) * width;
const toY = (val: number) => height - (val / maxY) * height;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-wrap gap-4 mb-6 justify-center">
<button
onClick={() => setShowLine(!showLine)}
className={`px-4 py-2 rounded-full font-bold text-sm transition-all ${showLine ? 'bg-indigo-600 text-white' : 'bg-slate-100 text-slate-600'}`}
>
{showLine ? 'Hide Line' : 'Show Line of Best Fit'}
</button>
<button
onClick={() => setShowResiduals(!showResiduals)}
className={`px-4 py-2 rounded-full font-bold text-sm transition-all ${showResiduals ? 'bg-indigo-600 text-white' : 'bg-slate-100 text-slate-600'}`}
>
{showResiduals ? 'Hide Residuals' : 'Show Residuals'}
</button>
<button
onClick={() => setHasOutlier(!hasOutlier)}
className={`px-4 py-2 rounded-full font-bold text-sm transition-all border ${hasOutlier ? 'bg-rose-100 text-rose-700 border-rose-300' : 'bg-white text-slate-600 border-slate-300'}`}
>
{hasOutlier ? 'Remove Outlier' : 'Add Outlier'}
</button>
</div>
<div className="relative border-b border-l border-slate-300 bg-slate-50 rounded-tr-lg mb-4 h-[250px]">
<svg width="100%" height="100%" viewBox={`0 0 ${width} ${height}`} className="overflow-visible">
{/* Line of Best Fit */}
{showLine && (
<line
x1={toX(0)} y1={toY(predict(0))}
x2={toX(maxX)} y2={toY(predict(maxX))}
stroke="#4f46e5" strokeWidth="2" strokeDasharray={hasOutlier ? "5,5" : ""}
/>
)}
{/* Residuals */}
{showLine && showResiduals && points.map((p, i) => (
<line
key={`res-${i}`}
x1={toX(p.x)} y1={toY(p.y)}
x2={toX(p.x)} y2={toY(predict(p.x))}
stroke={p.y > predict(p.x) ? "#10b981" : "#f43f5e"} strokeWidth="1.5" opacity="0.6"
/>
))}
{/* Points */}
{points.map((p, i) => (
<g key={i}>
<circle
cx={toX(p.x)} cy={toY(p.y)}
r={p.isOutlier ? 6 : 4}
fill={p.isOutlier ? "#f43f5e" : "#475569"}
stroke="white" strokeWidth="2"
className="transition-all duration-300"
/>
{p.isOutlier && (
<text x={toX(p.x)+10} y={toY(p.y)} className="text-xs font-bold fill-rose-600">Outlier</text>
)}
</g>
))}
</svg>
{/* Axes Labels */}
<div className="absolute -bottom-6 w-full text-center text-xs font-bold text-slate-400">Variable X</div>
<div className="absolute -left-8 top-1/2 -rotate-90 text-xs font-bold text-slate-400">Variable Y</div>
</div>
<div className="bg-slate-50 p-4 rounded-lg border border-slate-200 flex justify-between items-center text-sm">
<div>
<span className="font-bold text-slate-500 block text-xs uppercase">Slope (m)</span>
<span className="font-mono font-bold text-indigo-700 text-lg">{slope.toFixed(2)}</span>
</div>
{hasOutlier && (
<div className="text-rose-600 font-bold bg-rose-50 px-3 py-1 rounded border border-rose-200">
Outlier pulls the line down!
</div>
)}
</div>
</div>
);
};
export default ScatterplotInteractiveWidget;

View File

@ -0,0 +1,300 @@
import React, { useState, useRef, useEffect } from 'react';
type Mode = 'AA' | 'SAS' | 'SSS';
const SimilarityTestsWidget: React.FC = () => {
const [mode, setMode] = useState<Mode>('AA');
const [scale, setScale] = useState(1.5);
// Store Vertex B's position relative to A (x offset, y height)
// A is at (40, 220). SVG Y is down.
const [vertexB, setVertexB] = useState({ x: 40, y: 100 });
const isDragging = useRef(false);
const svgRef = useRef<SVGSVGElement>(null);
// Triangle 1 (ABC) - Fixed base AC
const A = { x: 40, y: 220 };
const C = { x: 120, y: 220 }; // Base length = 80
// Calculate B in SVG coordinates based on state
// vertexB.y is the height (upwards), so we subtract from A.y
const B = { x: A.x + vertexB.x, y: A.y - vertexB.y };
// Calculate lengths and angles for T1
const dist = (p1: {x:number, y:number}, p2: {x:number, y:number}) => Math.sqrt((p1.x - p2.x)**2 + (p1.y - p2.y)**2);
const c1 = dist(A, B); // side c (opp C) - Side AB
const a1 = dist(B, C); // side a (opp A) - Side BC
const b1 = dist(A, C); // side b (opp B) - Side AC (Base)
const getAngle = (a: number, b: number, c: number) => {
return Math.acos((b**2 + c**2 - a**2) / (2 * b * c)) * (180 / Math.PI);
};
const angleA = getAngle(a1, b1, c1);
const angleB = getAngle(b1, a1, c1);
// const angleC = getAngle(c1, a1, b1);
// Triangle 2 (DEF) - Scaled version of ABC
// Start D with enough margin. Max width of T1 is ~100-140.
// Let's place D at x=240.
const D = { x: 240, y: 220 };
// F is horizontal from D by scaled base length
const F = { x: D.x + b1 * scale, y: D.y };
// E is scaled vector AB from D
const vecAB = { x: B.x - A.x, y: B.y - A.y };
const E = {
x: D.x + vecAB.x * scale,
y: D.y + vecAB.y * scale
};
// Interaction
const handleMouseMove = (e: React.MouseEvent) => {
if (!isDragging.current || !svgRef.current) return;
const rect = svgRef.current.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// Constraints for B relative to A
// Keep B within reasonable bounds to prevent breaking the layout
// Base is 40 to 120. B.x can range from 0 to 140?
const newX = x - A.x;
const height = A.y - y;
// Clamp
const clampedX = Math.max(-20, Math.min(100, newX));
const clampedH = Math.max(40, Math.min(180, height));
setVertexB({ x: clampedX, y: clampedH });
};
const angleColor = "#6366f1"; // Indigo
const sideColor = "#059669"; // Emerald
// Helper: draw filled angle wedge + labelled badge at a vertex
const angleC = 180 - angleA - angleB;
const renderAngle = (
vx: number, vy: number,
p1x: number, p1y: number,
p2x: number, p2y: number,
deg: number,
r = 28
) => {
const d1 = Math.atan2(p1y - vy, p1x - vx);
const d2 = Math.atan2(p2y - vy, p2x - vx);
const sx = vx + r * Math.cos(d1), sy = vy + r * Math.sin(d1);
const ex = vx + r * Math.cos(d2), ey = vy + r * Math.sin(d2);
const cross = (p1x - vx) * (p2y - vy) - (p1y - vy) * (p2x - vx);
const sweep = cross > 0 ? 1 : 0;
let diff = d2 - d1;
while (diff > Math.PI) diff -= 2 * Math.PI;
while (diff < -Math.PI) diff += 2 * Math.PI;
const mid = d1 + diff / 2;
const lr = r + 18;
const lx = vx + lr * Math.cos(mid), ly = vy + lr * Math.sin(mid);
const txt = `${Math.round(deg)}°`;
return (
<g>
<path d={`M ${vx} ${vy} L ${sx} ${sy} A ${r} ${r} 0 0 ${sweep} ${ex} ${ey} Z`} fill={angleColor} fillOpacity={0.12} stroke={angleColor} strokeWidth={2} />
<rect x={lx - 18} y={ly - 10} width={36} height={20} rx={5} fill="white" fillOpacity={0.92} stroke={angleColor} strokeWidth={0.8} />
<text x={lx} y={ly + 5} textAnchor="middle" fill={angleColor} fontSize="13" fontWeight="bold" fontFamily="system-ui">{txt}</text>
</g>
);
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col sm:flex-row gap-4 justify-between items-center mb-6">
<div className="flex bg-slate-100 p-1 rounded-lg overflow-x-auto max-w-full">
{(['AA', 'SAS', 'SSS'] as Mode[]).map(m => (
<button
key={m}
onClick={() => setMode(m)}
className={`px-4 py-2 rounded-md text-sm font-bold transition-all whitespace-nowrap ${
mode === m
? 'bg-white text-rose-600 shadow-sm'
: 'text-slate-500 hover:text-rose-600'
}`}
>
{m}
</button>
))}
</div>
<div className="flex items-center gap-3 bg-slate-50 px-4 py-2 rounded-lg border border-slate-200">
<span className="text-xs font-bold text-slate-400 uppercase">Scale (k)</span>
<input
type="range" min="0.5" max="2.5" step="0.1"
value={scale}
onChange={e => setScale(parseFloat(e.target.value))}
className="w-24 h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-rose-600"
/>
<span className="font-mono font-bold text-rose-600 text-sm w-12 text-right">{scale.toFixed(1)}x</span>
</div>
</div>
<div className="relative border border-slate-100 rounded-lg bg-slate-50 mb-6 overflow-hidden flex justify-center">
<svg
ref={svgRef}
width="550" height="280"
className="cursor-default select-none"
onMouseMove={handleMouseMove}
onMouseUp={() => isDragging.current = false}
onMouseLeave={() => isDragging.current = false}
>
<defs>
<pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse">
<path d="M 20 0 L 0 0 0 20" fill="none" stroke="#e2e8f0" strokeWidth="0.5"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid)" />
{/* Triangle 1 (ABC) */}
<path d={`M ${A.x} ${A.y} L ${B.x} ${B.y} L ${C.x} ${C.y} Z`} fill="rgba(255, 255, 255, 0.8)" stroke="#334155" strokeWidth="2" />
{/* Vertices T1 */}
<circle cx={A.x} cy={A.y} r="4" fill="#334155" />
<text x={A.x - 16} y={A.y + 14} fontWeight="bold" fill="#334155" fontSize="14">A</text>
<circle cx={C.x} cy={C.y} r="4" fill="#334155" />
<text x={C.x + 8} y={C.y + 14} fontWeight="bold" fill="#334155" fontSize="14">C</text>
{/* Draggable B */}
<g onMouseDown={() => isDragging.current = true} className="cursor-grab active:cursor-grabbing">
<circle cx={B.x} cy={B.y} r="20" fill="transparent" /> {/* Hit area */}
<circle cx={B.x} cy={B.y} r="7" fill="#f43f5e" stroke="white" strokeWidth="2" />
<text x={B.x} y={B.y - 16} textAnchor="middle" fontWeight="bold" fill="#f43f5e" fontSize="14">B</text>
</g>
{/* Triangle 2 (DEF) */}
<path d={`M ${D.x} ${D.y} L ${E.x} ${E.y} L ${F.x} ${F.y} Z`} fill="rgba(255, 255, 255, 0.8)" stroke="#334155" strokeWidth="2" />
<circle cx={D.x} cy={D.y} r="4" fill="#334155" />
<text x={D.x - 16} y={D.y + 14} fontWeight="bold" fill="#334155" fontSize="14">D</text>
<circle cx={F.x} cy={F.y} r="4" fill="#334155" />
<text x={F.x + 8} y={F.y + 14} fontWeight="bold" fill="#334155" fontSize="14">F</text>
<circle cx={E.x} cy={E.y} r="4" fill="#334155" />
<text x={E.x} y={E.y - 16} textAnchor="middle" fontWeight="bold" fill="#334155" fontSize="14">E</text>
{/* Visual Overlays based on Mode */}
{mode === 'AA' && (
<>
{/* Angle A and D (base-left) */}
{renderAngle(A.x, A.y, C.x, C.y, B.x, B.y, angleA)}
{renderAngle(D.x, D.y, F.x, F.y, E.x, E.y, angleA)}
{/* Angle B and E (apex) */}
{renderAngle(B.x, B.y, A.x, A.y, C.x, C.y, angleB)}
{renderAngle(E.x, E.y, D.x, D.y, F.x, F.y, angleB)}
</>
)}
{mode === 'SAS' && (
<>
{/* Included Angle A and D */}
{renderAngle(A.x, A.y, C.x, C.y, B.x, B.y, angleA)}
{renderAngle(D.x, D.y, F.x, F.y, E.x, E.y, angleA)}
{/* Side labels with background badges */}
{/* Side AB / DE */}
<rect x={(A.x + B.x)/2 - 24} y={(A.y + B.y)/2 - 12} width={36} height={20} rx={5} fill="white" fillOpacity={0.92} stroke={sideColor} strokeWidth={0.8} />
<text x={(A.x + B.x)/2 - 6} y={(A.y + B.y)/2 + 3} fill={sideColor} fontSize="13" fontWeight="bold" textAnchor="middle">{Math.round(c1)}</text>
<rect x={(D.x + E.x)/2 - 24} y={(D.y + E.y)/2 - 12} width={36} height={20} rx={5} fill="white" fillOpacity={0.92} stroke={sideColor} strokeWidth={0.8} />
<text x={(D.x + E.x)/2 - 6} y={(D.y + E.y)/2 + 3} fill={sideColor} fontSize="13" fontWeight="bold" textAnchor="middle">{Math.round(c1 * scale)}</text>
{/* Side AC / DF */}
<rect x={(A.x + C.x)/2 - 18} y={A.y + 4} width={36} height={20} rx={5} fill="white" fillOpacity={0.92} stroke={sideColor} strokeWidth={0.8} />
<text x={(A.x + C.x)/2} y={A.y + 18} fill={sideColor} fontSize="13" fontWeight="bold" textAnchor="middle">{Math.round(b1)}</text>
<rect x={(D.x + F.x)/2 - 18} y={D.y + 4} width={36} height={20} rx={5} fill="white" fillOpacity={0.92} stroke={sideColor} strokeWidth={0.8} />
<text x={(D.x + F.x)/2} y={D.y + 18} fill={sideColor} fontSize="13" fontWeight="bold" textAnchor="middle">{Math.round(b1 * scale)}</text>
</>
)}
{mode === 'SSS' && (
<>
{/* Side AB / DE */}
<rect x={(A.x + B.x)/2 - 24} y={(A.y + B.y)/2 - 12} width={36} height={20} rx={5} fill="white" fillOpacity={0.92} stroke={sideColor} strokeWidth={0.8} />
<text x={(A.x + B.x)/2 - 6} y={(A.y + B.y)/2 + 3} fill={sideColor} fontSize="13" fontWeight="bold" textAnchor="middle">{Math.round(c1)}</text>
<rect x={(D.x + E.x)/2 - 24} y={(D.y + E.y)/2 - 12} width={36} height={20} rx={5} fill="white" fillOpacity={0.92} stroke={sideColor} strokeWidth={0.8} />
<text x={(D.x + E.x)/2 - 6} y={(D.y + E.y)/2 + 3} fill={sideColor} fontSize="13" fontWeight="bold" textAnchor="middle">{Math.round(c1 * scale)}</text>
{/* Side AC / DF */}
<rect x={(A.x + C.x)/2 - 18} y={A.y + 4} width={36} height={20} rx={5} fill="white" fillOpacity={0.92} stroke={sideColor} strokeWidth={0.8} />
<text x={(A.x + C.x)/2} y={A.y + 18} fill={sideColor} fontSize="13" fontWeight="bold" textAnchor="middle">{Math.round(b1)}</text>
<rect x={(D.x + F.x)/2 - 18} y={D.y + 4} width={36} height={20} rx={5} fill="white" fillOpacity={0.92} stroke={sideColor} strokeWidth={0.8} />
<text x={(D.x + F.x)/2} y={D.y + 18} fill={sideColor} fontSize="13" fontWeight="bold" textAnchor="middle">{Math.round(b1 * scale)}</text>
{/* Side BC / EF */}
<rect x={(B.x + C.x)/2 + 2} y={(B.y + C.y)/2 - 12} width={36} height={20} rx={5} fill="white" fillOpacity={0.92} stroke={sideColor} strokeWidth={0.8} />
<text x={(B.x + C.x)/2 + 20} y={(B.y + C.y)/2 + 3} fill={sideColor} fontSize="13" fontWeight="bold" textAnchor="middle">{Math.round(a1)}</text>
<rect x={(E.x + F.x)/2 + 2} y={(E.y + F.y)/2 - 12} width={36} height={20} rx={5} fill="white" fillOpacity={0.92} stroke={sideColor} strokeWidth={0.8} />
<text x={(E.x + F.x)/2 + 20} y={(E.y + F.y)/2 + 3} fill={sideColor} fontSize="13" fontWeight="bold" textAnchor="middle">{Math.round(a1 * scale)}</text>
</>
)}
</svg>
</div>
<div className="bg-rose-50 border border-rose-100 rounded-lg p-4 text-rose-900">
<h4 className="font-bold mb-2 flex items-center gap-2 text-lg">
<span className="w-3 h-3 rounded-full bg-rose-500"></span>
{mode === 'AA' && "Angle-Angle (AA) Similarity"}
{mode === 'SAS' && "Side-Angle-Side (SAS) Similarity"}
{mode === 'SSS' && "Side-Side-Side (SSS) Similarity"}
</h4>
<div className="text-sm font-mono space-y-2">
{mode === 'AA' && (
<>
<p className="leading-relaxed">If two angles of one triangle are equal to two angles of another triangle, then the triangles are similar.</p>
<div className="flex gap-8 mt-2">
<div>
<span className="text-xs font-bold text-rose-400 uppercase">First Angle</span>
<p className="font-bold text-lg">A = D = {Math.round(angleA)}°</p>
</div>
<div>
<span className="text-xs font-bold text-rose-400 uppercase">Second Angle</span>
<p className="font-bold text-lg">B = E = {Math.round(angleB)}°</p>
</div>
</div>
</>
)}
{mode === 'SAS' && (
<>
<p className="leading-relaxed">If two sides are proportional and the included angles are equal, the triangles are similar.</p>
<div className="grid grid-cols-2 gap-4 mt-2">
<div className="bg-white p-2 rounded border border-rose-100">
<p className="text-xs text-rose-500 font-bold uppercase">Side Ratio (c)</p>
<p>DE / AB = {(c1*scale).toFixed(0)} / {c1.toFixed(0)} = <strong>{scale.toFixed(1)}</strong></p>
</div>
<div className="bg-white p-2 rounded border border-rose-100">
<p className="text-xs text-rose-500 font-bold uppercase">Side Ratio (b)</p>
<p>DF / AC = {(b1*scale).toFixed(0)} / {b1.toFixed(0)} = <strong>{scale.toFixed(1)}</strong></p>
</div>
</div>
<p className="mt-2 font-bold text-rose-800">Included Angle: A = D = {Math.round(angleA)}°</p>
</>
)}
{mode === 'SSS' && (
<>
<p className="leading-relaxed">If the corresponding sides of two triangles are proportional, then the triangles are similar.</p>
<p className="bg-white inline-block px-2 py-1 rounded border border-rose-100 font-bold text-rose-600 mb-2">Scale Factor k = {scale.toFixed(1)}</p>
<div className="grid grid-cols-3 gap-2 text-center text-xs">
<div className="bg-white p-1 rounded">
DE/AB = {scale.toFixed(1)}
</div>
<div className="bg-white p-1 rounded">
EF/BC = {scale.toFixed(1)}
</div>
<div className="bg-white p-1 rounded">
DF/AC = {scale.toFixed(1)}
</div>
</div>
</>
)}
</div>
<p className="text-xs text-rose-400 mt-4 border-t border-rose-100 pt-2">
Drag vertex <strong>B</strong> on the first triangle to explore different shapes!
</p>
</div>
</div>
);
};
export default SimilarityTestsWidget;

View File

@ -0,0 +1,119 @@
import React, { useState, useRef, useEffect } from 'react';
const SimilarityWidget: React.FC = () => {
const [ratio, setRatio] = useState(0.5); // Position of D along AB (0 to 1)
const isDragging = useRef(false);
const svgRef = useRef<SVGSVGElement>(null);
// Triangle Vertices
const A = { x: 200, y: 50 };
const B = { x: 50, y: 300 };
const C = { x: 350, y: 300 };
// Calculate D and E based on ratio
const D = {
x: A.x + (B.x - A.x) * ratio,
y: A.y + (B.y - A.y) * ratio
};
const E = {
x: A.x + (C.x - A.x) * ratio,
y: A.y + (C.y - A.y) * ratio
};
const handleInteraction = (clientY: number) => {
if (!svgRef.current) return;
const rect = svgRef.current.getBoundingClientRect();
const y = clientY - rect.top;
// Clamp y between A.y and B.y
const clampedY = Math.max(A.y, Math.min(B.y, y));
// Calculate new ratio
const newRatio = (clampedY - A.y) / (B.y - A.y);
setRatio(Math.max(0.1, Math.min(0.9, newRatio))); // clamp to avoid degenerate
};
const handleMouseDown = (e: React.MouseEvent) => {
isDragging.current = true;
handleInteraction(e.clientY);
};
const handleMouseMove = (e: React.MouseEvent) => {
if (isDragging.current) {
handleInteraction(e.clientY);
}
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200 flex flex-col md:flex-row items-center gap-8">
<svg
ref={svgRef}
width="400"
height="350"
className="select-none cursor-ns-resize"
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={() => isDragging.current = false}
onMouseLeave={() => isDragging.current = false}
>
{/* Main Triangle */}
<path d={`M ${A.x} ${A.y} L ${B.x} ${B.y} L ${C.x} ${C.y} Z`} fill="none" stroke="#e2e8f0" strokeWidth="2" />
{/* Filled Top Triangle (Similar) */}
<path d={`M ${A.x} ${A.y} L ${D.x} ${D.y} L ${E.x} ${E.y} Z`} fill="rgba(244, 63, 94, 0.1)" stroke="none" />
{/* Parallel Line DE */}
<line x1={D.x} y1={D.y} x2={E.x} y2={E.y} stroke="#e11d48" strokeWidth="3" />
{/* Labels */}
<text x={A.x} y={A.y - 10} textAnchor="middle" fontWeight="bold" fill="#64748b">A</text>
<text x={B.x - 10} y={B.y} textAnchor="end" fontWeight="bold" fill="#64748b">B</text>
<text x={C.x + 10} y={C.y} textAnchor="start" fontWeight="bold" fill="#64748b">C</text>
<text x={D.x - 10} y={D.y} textAnchor="end" fontWeight="bold" fill="#e11d48">D</text>
<text x={E.x + 10} y={E.y} textAnchor="start" fontWeight="bold" fill="#e11d48">E</text>
{/* Drag Handle */}
<circle cx={D.x} cy={D.y} r="6" fill="#e11d48" stroke="white" strokeWidth="2" />
<circle cx={E.x} cy={E.y} r="6" fill="#e11d48" stroke="white" strokeWidth="2" />
</svg>
<div className="flex-1 w-full">
<h3 className="text-lg font-bold text-slate-800 mb-4">Triangle Proportionality</h3>
<p className="text-sm text-slate-500 mb-6">Drag the red line. Because DE || BC, the small triangle is similar to the large triangle.</p>
<div className="space-y-4">
<div className="bg-slate-50 p-4 rounded-lg border-l-4 border-rose-500">
<p className="text-xs font-bold text-slate-400 uppercase mb-1">Scale Factor</p>
<p className="font-mono text-xl text-rose-700">{ratio.toFixed(2)}</p>
</div>
<div className="bg-white border border-slate-200 p-4 rounded-lg shadow-sm">
<p className="font-mono text-sm mb-2 text-slate-600">Corresponding Sides Ratio:</p>
<div className="flex items-center justify-between font-mono font-bold text-lg">
<div className="text-rose-600">AD / AB</div>
<div className="text-slate-400">=</div>
<div className="text-rose-600">AE / AC</div>
<div className="text-slate-400">=</div>
<div className="text-rose-600">{ratio.toFixed(2)}</div>
</div>
</div>
<div className="bg-white border border-slate-200 p-4 rounded-lg shadow-sm">
<p className="font-mono text-sm mb-2 text-slate-600">Area Ratio (k²):</p>
<div className="flex items-center justify-between font-mono font-bold text-lg">
<div className="text-rose-600">Area(ADE)</div>
<div className="text-slate-400">/</div>
<div className="text-slate-600">Area(ABC)</div>
<div className="text-slate-400">=</div>
<div className="text-rose-600">{(ratio * ratio).toFixed(2)}</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default SimilarityWidget;

View File

@ -0,0 +1,93 @@
import React, { useState } from 'react';
const SlopeInterceptWidget: React.FC = () => {
const [m, setM] = useState(2);
const [b, setB] = useState(1);
// Visualization config
const range = 10;
const scale = 25; // px per unit
const center = 150;
const toPx = (val: number, isY = false) => isY ? center - val * scale : center + val * scale;
// Points for triangle
const p1 = { x: 0, y: b };
const p2 = { x: 1, y: m * 1 + b };
// Triangle vertex (1, b)
const p3 = { x: 1, y: b };
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8">
<div className="w-full md:w-1/3 space-y-6">
<div className="p-4 bg-slate-50 rounded-xl border border-slate-200 text-center">
<div className="text-sm text-slate-500 font-bold uppercase mb-1">Equation</div>
<div className="text-2xl font-mono font-bold text-slate-800">
y = <span className="text-blue-600">{m}</span>x + <span className="text-rose-600">{b}</span>
</div>
</div>
<div>
<label className="text-xs font-bold text-blue-600 uppercase">Slope (m) = {m}</label>
<input
type="range" min="-5" max="5" step="0.5"
value={m} onChange={e => setM(parseFloat(e.target.value))}
className="w-full h-2 bg-blue-100 rounded-lg appearance-none cursor-pointer accent-blue-600 mt-2"
/>
<p className="text-xs text-slate-400 mt-1">Rate of Change (Rise / Run)</p>
</div>
<div>
<label className="text-xs font-bold text-rose-600 uppercase">Y-Intercept (b) = {b}</label>
<input
type="range" min="-5" max="5" step="1"
value={b} onChange={e => setB(parseFloat(e.target.value))}
className="w-full h-2 bg-rose-100 rounded-lg appearance-none cursor-pointer accent-rose-600 mt-2"
/>
<p className="text-xs text-slate-400 mt-1">Starting Value (when x=0)</p>
</div>
</div>
<div className="w-full md:flex-1 h-[300px] bg-white border border-slate-200 rounded-xl relative overflow-hidden">
<svg width="100%" height="100%" viewBox="0 0 300 300" className="absolute top-0 left-0">
<defs>
<pattern id="si-grid" width={scale} height={scale} patternUnits="userSpaceOnUse">
<path d={`M ${scale} 0 L 0 0 0 ${scale}`} fill="none" stroke="#f1f5f9" strokeWidth="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#si-grid)" />
{/* Axes */}
<line x1="0" y1={center} x2="300" y2={center} stroke="#cbd5e1" strokeWidth="2" />
<line x1={center} y1="0" x2={center} y2="300" stroke="#cbd5e1" strokeWidth="2" />
{/* The Line */}
<line
x1={toPx(-range)} y1={toPx(m * -range + b, true)}
x2={toPx(range)} y2={toPx(m * range + b, true)}
stroke="#1e293b" strokeWidth="3"
/>
{/* Slope Triangle (between x=0 and x=1) */}
<path
d={`M ${toPx(p1.x)} ${toPx(p1.y, true)} L ${toPx(p3.x)} ${toPx(p3.y, true)} L ${toPx(p2.x)} ${toPx(p2.y, true)} Z`}
fill="rgba(37, 99, 235, 0.1)" stroke="#2563eb" strokeWidth="1" strokeDasharray="4,2"
/>
{/* Intercept Point */}
<circle cx={toPx(0)} cy={toPx(b, true)} r="5" fill="#e11d48" stroke="white" strokeWidth="2" />
<text x={toPx(0) + 10} y={toPx(b, true)} className="text-xs font-bold fill-rose-600">b={b}</text>
{/* Rise/Run Labels */}
<text x={toPx(0.5)} y={toPx(b, true) + (m>0 ? 15 : -10)} textAnchor="middle" className="text-[10px] font-bold fill-blue-400">Run: 1</text>
<text x={toPx(1) + 5} y={toPx(b + m/2, true)} className="text-[10px] font-bold fill-blue-600">Rise: {m}</text>
</svg>
</div>
</div>
</div>
);
};
export default SlopeInterceptWidget;

View File

@ -0,0 +1,121 @@
import React, { useState } from 'react';
const StandardFormWidget: React.FC = () => {
const [A, setA] = useState(2);
const [B, setB] = useState(3);
const [C, setC] = useState(12);
// Intercepts
const xInt = A !== 0 ? C / A : null;
const yInt = B !== 0 ? C / B : null;
// Vis
const range = 15;
const scale = 15;
const center = 150;
const toPx = (val: number, isY = false) => isY ? center - val * scale : center + val * scale;
// Line points
// If B!=0, y = (C - Ax)/B. If A!=0, x = (C - By)/A.
let p1, p2;
if (B !== 0) {
p1 = { x: -range, y: (C - A * -range) / B };
p2 = { x: range, y: (C - A * range) / B };
} else {
// Vertical line x = C/A
p1 = { x: C/A, y: -range };
p2 = { x: C/A, y: range };
}
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col gap-6">
<div className="flex justify-center mb-4">
<div className="px-6 py-3 bg-slate-800 text-white rounded-xl shadow-md text-2xl font-mono font-bold tracking-wider">
{A}x + {B}y = {C}
</div>
</div>
<div className="grid grid-cols-3 gap-4 mb-4">
<div className="bg-indigo-50 p-3 rounded-lg border border-indigo-100">
<label className="text-xs font-bold text-indigo-800 uppercase block mb-1">A (x-coeff)</label>
<input type="number" value={A} onChange={e => setA(Number(e.target.value))} className="w-full p-1 border rounded text-center font-bold"/>
</div>
<div className="bg-emerald-50 p-3 rounded-lg border border-emerald-100">
<label className="text-xs font-bold text-emerald-800 uppercase block mb-1">B (y-coeff)</label>
<input type="number" value={B} onChange={e => setB(Number(e.target.value))} className="w-full p-1 border rounded text-center font-bold"/>
</div>
<div className="bg-amber-50 p-3 rounded-lg border border-amber-100">
<label className="text-xs font-bold text-amber-800 uppercase block mb-1">C (constant)</label>
<input type="number" value={C} onChange={e => setC(Number(e.target.value))} className="w-full p-1 border rounded text-center font-bold"/>
</div>
</div>
<div className="flex flex-col md:flex-row gap-8">
<div className="w-full md:w-1/3 space-y-4">
<div className="p-4 bg-slate-50 rounded-lg border border-slate-200">
<h4 className="font-bold text-slate-700 mb-2 border-b pb-1">Cover-Up Method</h4>
<div className="mb-4">
<p className="text-xs text-slate-500 uppercase font-bold mb-1">Find X-Intercept (Set y=0)</p>
<div className="font-mono text-sm bg-white p-2 rounded border border-slate-200 text-slate-600">
{A}x = {C} <br/>
x = {C} / {A} <br/>
<span className="text-indigo-600 font-bold">x = {xInt !== null ? xInt.toFixed(2) : 'Undefined'}</span>
</div>
</div>
<div>
<p className="text-xs text-slate-500 uppercase font-bold mb-1">Find Y-Intercept (Set x=0)</p>
<div className="font-mono text-sm bg-white p-2 rounded border border-slate-200 text-slate-600">
{B}y = {C} <br/>
y = {C} / {B} <br/>
<span className="text-emerald-600 font-bold">y = {yInt !== null ? yInt.toFixed(2) : 'Undefined'}</span>
</div>
</div>
</div>
</div>
<div className="w-full md:flex-1 h-[300px] border border-slate-200 rounded-lg relative bg-white overflow-hidden">
<svg width="100%" height="100%" viewBox="0 0 300 300" className="absolute">
{/* Grid */}
<defs>
<pattern id="sf-grid" width={scale} height={scale} patternUnits="userSpaceOnUse">
<path d={`M ${scale} 0 L 0 0 0 ${scale}`} fill="none" stroke="#f1f5f9" strokeWidth="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#sf-grid)" />
{/* Axes */}
<line x1="0" y1={center} x2="300" y2={center} stroke="#94a3b8" strokeWidth="2" />
<line x1={center} y1="0" x2={center} y2="300" stroke="#94a3b8" strokeWidth="2" />
{/* Line */}
<line
x1={toPx(p1.x)} y1={toPx(p1.y, true)}
x2={toPx(p2.x)} y2={toPx(p2.y, true)}
stroke="#0f172a" strokeWidth="3"
/>
{/* Intercepts */}
{xInt !== null && Math.abs(xInt) <= range && (
<g>
<circle cx={toPx(xInt)} cy={center} r="5" fill="#4f46e5" stroke="white" strokeWidth="2"/>
<text x={toPx(xInt)} y={center + 20} textAnchor="middle" className="text-xs font-bold fill-indigo-700">{xInt.toFixed(1)}</text>
</g>
)}
{yInt !== null && Math.abs(yInt) <= range && (
<g>
<circle cx={center} cy={toPx(yInt, true)} r="5" fill="#10b981" stroke="white" strokeWidth="2"/>
<text x={center + 10} y={toPx(yInt, true)} dominantBaseline="middle" className="text-xs font-bold fill-emerald-700">{yInt.toFixed(1)}</text>
</g>
)}
</svg>
</div>
</div>
</div>
</div>
);
};
export default StandardFormWidget;

View File

@ -0,0 +1,88 @@
import React, { useState } from 'react';
import { ArrowRight, Users, FlaskConical } from 'lucide-react';
const StudyDesignWidget: React.FC = () => {
const [isRandomSample, setIsRandomSample] = useState(false);
const [isRandomAssign, setIsRandomAssign] = useState(false);
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
{/* Sampling */}
<div className={`p-4 rounded-xl border-2 cursor-pointer transition-all ${isRandomSample ? 'border-amber-500 bg-amber-50' : 'border-slate-200 hover:border-amber-200'}`}
onClick={() => setIsRandomSample(!isRandomSample)}>
<div className="flex items-center gap-3 mb-2">
<div className={`w-8 h-8 rounded-full flex items-center justify-center ${isRandomSample ? 'bg-amber-500 text-white' : 'bg-slate-200'}`}>
<Users className="w-4 h-4" />
</div>
<h4 className="font-bold text-slate-800">Selection Method</h4>
</div>
<p className="text-sm text-slate-600 mb-3">How were participants chosen?</p>
<div className="flex justify-between items-center bg-white p-2 rounded border border-slate-100">
<span className="text-xs font-bold uppercase text-slate-400">Current:</span>
<span className={`font-bold ${isRandomSample ? 'text-amber-600' : 'text-slate-500'}`}>
{isRandomSample ? "Random Sample" : "Convenience / Voluntary"}
</span>
</div>
</div>
{/* Assignment */}
<div className={`p-4 rounded-xl border-2 cursor-pointer transition-all ${isRandomAssign ? 'border-amber-500 bg-amber-50' : 'border-slate-200 hover:border-amber-200'}`}
onClick={() => setIsRandomAssign(!isRandomAssign)}>
<div className="flex items-center gap-3 mb-2">
<div className={`w-8 h-8 rounded-full flex items-center justify-center ${isRandomAssign ? 'bg-amber-500 text-white' : 'bg-slate-200'}`}>
<FlaskConical className="w-4 h-4" />
</div>
<h4 className="font-bold text-slate-800">Assignment Method</h4>
</div>
<p className="text-sm text-slate-600 mb-3">How were treatments assigned?</p>
<div className="flex justify-between items-center bg-white p-2 rounded border border-slate-100">
<span className="text-xs font-bold uppercase text-slate-400">Current:</span>
<span className={`font-bold ${isRandomAssign ? 'text-amber-600' : 'text-slate-500'}`}>
{isRandomAssign ? "Random Assignment" : "Observational / None"}
</span>
</div>
</div>
</div>
{/* Conclusions */}
<div className="bg-slate-900 text-white p-6 rounded-xl relative overflow-hidden">
<div className="relative z-10 grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h4 className="text-slate-400 text-xs font-bold uppercase mb-1">Generalization</h4>
<p className="text-lg font-bold mb-2">
Can apply to Population?
</p>
<div className={`inline-flex items-center gap-2 px-3 py-1 rounded-full font-bold text-sm ${isRandomSample ? 'bg-green-500 text-white' : 'bg-red-500 text-white'}`}>
{isRandomSample ? <ArrowRight className="w-4 h-4" /> : null}
{isRandomSample ? "YES" : "NO (Sample Only)"}
</div>
<p className="text-xs text-slate-400 mt-2">
{isRandomSample
? "Random sampling reduces bias, allowing results to represent the whole population."
: "Without random sampling, results may be biased and only apply to the specific people studied."}
</p>
</div>
<div>
<h4 className="text-slate-400 text-xs font-bold uppercase mb-1">Causation</h4>
<p className="text-lg font-bold mb-2">
Can prove Cause & Effect?
</p>
<div className={`inline-flex items-center gap-2 px-3 py-1 rounded-full font-bold text-sm ${isRandomAssign ? 'bg-green-500 text-white' : 'bg-red-500 text-white'}`}>
{isRandomAssign ? <ArrowRight className="w-4 h-4" /> : null}
{isRandomAssign ? "YES" : "NO (Association Only)"}
</div>
<p className="text-xs text-slate-400 mt-2">
{isRandomAssign
? "Random assignment creates comparable groups, so differences can be attributed to the treatment."
: "Without random assignment (experiment), confounding variables might explain the difference."}
</p>
</div>
</div>
</div>
</div>
);
};
export default StudyDesignWidget;

View File

@ -0,0 +1,108 @@
import React, { useState } from 'react';
const SystemVisualizerWidget: React.FC = () => {
// Line 1: y = m1x + b1
const [m1, setM1] = useState(1);
const [b1, setB1] = useState(2);
// Line 2: y = m2x + b2
const [m2, setM2] = useState(-1);
const [b2, setB2] = useState(6);
// Visualization params
const range = 10;
const scale = 20;
const size = 300;
const center = size / 2;
const toPx = (v: number, isY = false) => {
return isY ? center - v * scale : center + v * scale;
};
// Logic
let intersectX = 0;
let intersectY = 0;
let solutionType = 'one'; // 'one', 'none', 'inf'
if (m1 === m2) {
if (b1 === b2) solutionType = 'inf';
else solutionType = 'none';
} else {
intersectX = (b2 - b1) / (m1 - m2);
intersectY = m1 * intersectX + b1;
}
const getLinePath = (m: number, b: number) => {
const x1 = -range;
const y1 = m * x1 + b;
const x2 = range;
const y2 = m * x2 + b;
return `M ${toPx(x1)} ${toPx(y1, true)} L ${toPx(x2)} ${toPx(y2, true)}`;
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8">
<div className="w-full md:w-1/3 space-y-6">
{/* Line 1 */}
<div className="p-4 bg-indigo-50 border border-indigo-100 rounded-lg">
<div className="flex justify-between items-center mb-2">
<span className="font-bold text-indigo-800 text-sm">Line 1: y = {m1}x + {b1}</span>
</div>
<div className="space-y-2">
<input type="range" min="-4" max="4" step="0.5" value={m1} onChange={e => setM1(parseFloat(e.target.value))} className="w-full h-1 bg-indigo-200 rounded accent-indigo-600"/>
<input type="range" min="-8" max="8" step="1" value={b1} onChange={e => setB1(parseFloat(e.target.value))} className="w-full h-1 bg-indigo-200 rounded accent-indigo-600"/>
</div>
</div>
{/* Line 2 */}
<div className="p-4 bg-rose-50 border border-rose-100 rounded-lg">
<div className="flex justify-between items-center mb-2">
<span className="font-bold text-rose-800 text-sm">Line 2: y = {m2}x + {b2}</span>
</div>
<div className="space-y-2">
<input type="range" min="-4" max="4" step="0.5" value={m2} onChange={e => setM2(parseFloat(e.target.value))} className="w-full h-1 bg-rose-200 rounded accent-rose-600"/>
<input type="range" min="-8" max="8" step="1" value={b2} onChange={e => setB2(parseFloat(e.target.value))} className="w-full h-1 bg-rose-200 rounded accent-rose-600"/>
</div>
</div>
{/* Result */}
<div className={`p-4 rounded-lg text-center font-bold border-2 ${
solutionType === 'one' ? 'bg-emerald-50 border-emerald-200 text-emerald-800' :
solutionType === 'none' ? 'bg-slate-50 border-slate-200 text-slate-500' :
'bg-amber-50 border-amber-200 text-amber-800'
}`}>
{solutionType === 'one' && `Intersection: (${intersectX.toFixed(1)}, ${intersectY.toFixed(1)})`}
{solutionType === 'none' && "No Solution (Parallel Lines)"}
{solutionType === 'inf' && "Infinite Solutions (Same Line)"}
</div>
</div>
<div className="flex-1 flex justify-center">
<div className="relative w-[300px] h-[300px] bg-white border border-slate-200 rounded-xl overflow-hidden">
<svg width="300" height="300" viewBox="0 0 300 300">
<defs>
<pattern id="grid-sys" width="20" height="20" patternUnits="userSpaceOnUse">
<path d="M 20 0 L 0 0 0 20" fill="none" stroke="#f1f5f9" strokeWidth="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid-sys)" />
<line x1="0" y1={center} x2={size} y2={center} stroke="#cbd5e1" strokeWidth="2" />
<line x1={center} y1="0" x2={center} y2={size} stroke="#cbd5e1" strokeWidth="2" />
<path d={getLinePath(m1, b1)} stroke="#4f46e5" strokeWidth="3" />
<path d={getLinePath(m2, b2)} stroke="#e11d48" strokeWidth="3" strokeDasharray={solutionType === 'inf' ? "5,5" : ""} />
{solutionType === 'one' && (
<circle cx={toPx(intersectX)} cy={toPx(intersectY, true)} r="5" fill="#10b981" stroke="white" strokeWidth="2" />
)}
</svg>
</div>
</div>
</div>
</div>
);
};
export default SystemVisualizerWidget;

View File

@ -0,0 +1,179 @@
import React, { useState, useRef } from 'react';
const TangentPropertiesWidget: React.FC = () => {
const [pointP, setPointP] = useState({ x: 350, y: 150 });
const isDragging = useRef(false);
const svgRef = useRef<SVGSVGElement>(null);
const center = { x: 150, y: 150 };
const radius = 60;
// Interaction
const handleMouseMove = (e: React.MouseEvent) => {
if (!isDragging.current || !svgRef.current) return;
const rect = svgRef.current.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// Constrain P to be outside the circle (distance > radius)
const dx = x - center.x;
const dy = y - center.y;
const dist = Math.sqrt(dx * dx + dy * dy);
// Min distance to keep things looking nice (radius + padding)
if (dist < radius + 20) {
const angle = Math.atan2(dy, dx);
setPointP({
x: center.x + (radius + 20) * Math.cos(angle),
y: center.y + (radius + 20) * Math.sin(angle)
});
} else {
setPointP({ x, y });
}
};
// Calculations
const dx = pointP.x - center.x;
const dy = pointP.y - center.y;
const distPO = Math.sqrt(dx * dx + dy * dy);
const anglePO = Math.atan2(dy, dx);
// Angle offset to tangent points
// cos(theta) = Adjacent / Hypotenuse = radius / distPO
const theta = Math.acos(radius / distPO);
const t1Angle = anglePO - theta;
const t2Angle = anglePO + theta;
const T1 = {
x: center.x + radius * Math.cos(t1Angle),
y: center.y + radius * Math.sin(t1Angle)
};
const T2 = {
x: center.x + radius * Math.cos(t2Angle),
y: center.y + radius * Math.sin(t2Angle)
};
const tangentLength = Math.sqrt(distPO * distPO - radius * radius);
// Right Angle Markers
const markerSize = 10;
const getRightAnglePath = (p: {x:number, y:number}, angle: number) => {
// angle is the angle of the radius. We need to go inwards and perpendicular
// Actually simpler: Vector from Center to T, and Vector T to P are perp.
// Let's just draw a small square aligned with radius
const rAngle = angle;
// Point on radius
const p1 = { x: p.x - markerSize * Math.cos(rAngle), y: p.y - markerSize * Math.sin(rAngle) };
// Point on tangent (towards P)
// Tangent is perpendicular to radius.
// We need to know if we go clockwise or counter clockwise.
// Vector T->P
const tpAngle = Math.atan2(pointP.y - p.y, pointP.x - p.x);
const p2 = { x: p.x + markerSize * Math.cos(tpAngle), y: p.y + markerSize * Math.sin(tpAngle) };
// Corner
const p3 = { x: p1.x + markerSize * Math.cos(tpAngle), y: p1.y + markerSize * Math.sin(tpAngle) };
return `M ${p1.x} ${p1.y} L ${p3.x} ${p3.y} L ${p2.x} ${p2.y}`;
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200 flex flex-col md:flex-row gap-8 items-center">
<div className="relative">
<svg
ref={svgRef}
width="400" height="300"
className="select-none cursor-default bg-slate-50 rounded-lg border border-slate-100"
onMouseMove={handleMouseMove}
onMouseUp={() => isDragging.current = false}
onMouseLeave={() => isDragging.current = false}
>
{/* Circle */}
<circle cx={center.x} cy={center.y} r={radius} fill="white" stroke="#94a3b8" strokeWidth="2" />
<circle cx={center.x} cy={center.y} r="3" fill="#64748b" />
<text x={center.x - 15} y={center.y + 5} className="text-xs font-bold fill-slate-400">O</text>
{/* Radii */}
<line x1={center.x} y1={center.y} x2={T1.x} y2={T1.y} stroke="#cbd5e1" strokeWidth="2" strokeDasharray="4,4" />
<line x1={center.x} y1={center.y} x2={T2.x} y2={T2.y} stroke="#cbd5e1" strokeWidth="2" strokeDasharray="4,4" />
{/* Tangents */}
<line x1={pointP.x} y1={pointP.y} x2={T1.x} y2={T1.y} stroke="#7c3aed" strokeWidth="3" />
<line x1={pointP.x} y1={pointP.y} x2={T2.x} y2={T2.y} stroke="#7c3aed" strokeWidth="3" />
{/* Right Angle Markers */}
<path d={getRightAnglePath(T1, t1Angle)} stroke="#64748b" fill="transparent" strokeWidth="1" />
<path d={getRightAnglePath(T2, t2Angle)} stroke="#64748b" fill="transparent" strokeWidth="1" />
{/* Points */}
<circle cx={T1.x} cy={T1.y} r="5" fill="#7c3aed" />
<text x={T1.x + (T1.x - center.x)*0.2} y={T1.y + (T1.y - center.y)*0.2} className="text-xs font-bold fill-violet-700">A</text>
<circle cx={T2.x} cy={T2.y} r="5" fill="#7c3aed" />
<text x={T2.x + (T2.x - center.x)*0.2} y={T2.y + (T2.y - center.y)*0.2} className="text-xs font-bold fill-violet-700">B</text>
{/* External Point P */}
<g
onMouseDown={() => isDragging.current = true}
className="cursor-grab active:cursor-grabbing"
>
<circle cx={pointP.x} cy={pointP.y} r="15" fill="transparent" />
<circle cx={pointP.x} cy={pointP.y} r="6" fill="#f43f5e" stroke="white" strokeWidth="2" />
<text x={pointP.x + 10} y={pointP.y} className="text-sm font-bold fill-rose-600">P</text>
</g>
{/* Length Labels (Midpoints) */}
<rect
x={(pointP.x + T1.x)/2 - 15} y={(pointP.y + T1.y)/2 - 10}
width="30" height="20" rx="4" fill="white" stroke="#e2e8f0"
/>
<text x={(pointP.x + T1.x)/2} y={(pointP.y + T1.y)/2 + 4} textAnchor="middle" className="text-xs font-bold fill-violet-600">
{Math.round(tangentLength)}
</text>
<rect
x={(pointP.x + T2.x)/2 - 15} y={(pointP.y + T2.y)/2 - 10}
width="30" height="20" rx="4" fill="white" stroke="#e2e8f0"
/>
<text x={(pointP.x + T2.x)/2} y={(pointP.y + T2.y)/2 + 4} textAnchor="middle" className="text-xs font-bold fill-violet-600">
{Math.round(tangentLength)}
</text>
</svg>
</div>
<div className="flex-1 space-y-6">
<div className="bg-violet-50 p-4 rounded-xl border border-violet-100">
<h4 className="font-bold text-violet-900 mb-2 flex items-center gap-2">
<span className="bg-violet-200 text-xs px-2 py-0.5 rounded-full text-violet-800">Rule 1</span>
Equal Tangents
</h4>
<p className="text-sm text-violet-800 mb-2">
Tangents from the same external point are always congruent.
</p>
<p className="font-mono text-lg font-bold text-violet-600 bg-white p-2 rounded border border-violet-100 text-center">
PA = PB = {Math.round(tangentLength)}
</p>
</div>
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200">
<h4 className="font-bold text-slate-700 mb-2 flex items-center gap-2">
<span className="bg-slate-200 text-xs px-2 py-0.5 rounded-full text-slate-600">Rule 2</span>
Perpendicular Radius
</h4>
<p className="text-sm text-slate-600">
The radius to the point of tangency is always perpendicular to the tangent line.
</p>
<div className="flex gap-4 mt-2 justify-center">
<span className="text-xs font-bold bg-white px-2 py-1 rounded border border-slate-200">OAP = 90°</span>
<span className="text-xs font-bold bg-white px-2 py-1 rounded border border-slate-200">OBP = 90°</span>
</div>
</div>
<p className="text-xs text-center text-slate-400">Drag point <strong>P</strong> to verify!</p>
</div>
</div>
);
};
export default TangentPropertiesWidget;

View File

@ -0,0 +1,233 @@
import React, { useState, useRef, useEffect } from 'react';
const SPECIAL_ANGLES = [0, 30, 45, 60, 90, 120, 135, 150, 180, 210, 225, 240, 270, 300, 315, 330, 360];
const UnitCircleWidget: React.FC = () => {
const [angle, setAngle] = useState(45); // Degrees
const [snap, setSnap] = useState(true); // Snap to special angles
const svgRef = useRef<SVGSVGElement>(null);
const isDragging = useRef(false);
const radius = 140;
const center = { x: 200, y: 200 };
const handleInteraction = (clientX: number, clientY: number) => {
if (!svgRef.current) return;
const rect = svgRef.current.getBoundingClientRect();
const dx = clientX - rect.left - center.x;
const dy = clientY - rect.top - center.y;
// Calculate angle from 0 to 360
let rad = Math.atan2(-dy, dx);
if (rad < 0) rad += 2 * Math.PI;
let deg = (rad * 180) / Math.PI;
if (snap) {
const nearest = SPECIAL_ANGLES.reduce((prev, curr) =>
Math.abs(curr - deg) < Math.abs(prev - deg) ? curr : prev
);
if (Math.abs(nearest - deg) < 15) {
deg = nearest;
}
}
if (deg > 360) deg = 360;
setAngle(Math.round(deg));
};
const handleMouseDown = (e: React.MouseEvent) => {
isDragging.current = true;
handleInteraction(e.clientX, e.clientY);
};
const handleMouseMove = (e: React.MouseEvent) => {
if (isDragging.current) {
handleInteraction(e.clientX, e.clientY);
}
};
const handleMouseUp = () => {
isDragging.current = false;
};
useEffect(() => {
const upHandler = () => isDragging.current = false;
window.addEventListener('mouseup', upHandler);
return () => window.removeEventListener('mouseup', upHandler);
}, []);
const rad = (angle * Math.PI) / 180;
const x = Math.cos(rad);
const y = Math.sin(rad);
const px = center.x + radius * x;
const py = center.y - radius * y;
const getExactValue = (val: number) => {
if (Math.abs(val) < 0.01) return "0";
if (Math.abs(val - 0.5) < 0.01) return "1/2";
if (Math.abs(val + 0.5) < 0.01) return "-1/2";
if (Math.abs(val - Math.sqrt(2)/2) < 0.01) return "√2/2";
if (Math.abs(val + Math.sqrt(2)/2) < 0.01) return "-√2/2";
if (Math.abs(val - Math.sqrt(3)/2) < 0.01) return "√3/2";
if (Math.abs(val + Math.sqrt(3)/2) < 0.01) return "-√3/2";
if (Math.abs(val - 1) < 0.01) return "1";
if (Math.abs(val + 1) < 0.01) return "-1";
return val.toFixed(3);
};
const getRadianLabel = (deg: number) => {
// Removed Record type annotation to prevent parsing error
const map: any = {
0: "0", 30: "π/6", 45: "π/4", 60: "π/3", 90: "π/2",
120: "2π/3", 135: "3π/4", 150: "5π/6", 180: "π",
210: "7π/6", 225: "5π/4", 240: "4π/3", 270: "3π/2",
300: "5π/3", 315: "7π/4", 330: "11π/6", 360: "2π"
};
if (map[deg]) return map[deg];
return ((deg * Math.PI) / 180).toFixed(2);
};
const cosStr = getExactValue(x);
const sinStr = getExactValue(y);
const getAngleColor = () => {
if (angle < 90) return "text-emerald-600";
if (angle < 180) return "text-indigo-600";
if (angle < 270) return "text-amber-600";
return "text-rose-600";
};
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200 flex flex-col md:flex-row gap-8 select-none">
<div className="flex-shrink-0 flex flex-col items-center">
<svg
ref={svgRef}
width="400"
height="400"
className="cursor-pointer touch-none"
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
>
<line x1="200" y1="20" x2="200" y2="380" stroke="#f1f5f9" strokeWidth="1" />
<line x1="20" y1="200" x2="380" y2="200" stroke="#f1f5f9" strokeWidth="1" />
<line x1="200" y1="40" x2="200" y2="360" stroke="#cbd5e1" strokeWidth="1" />
<line x1="40" y1="200" x2="360" y2="200" stroke="#cbd5e1" strokeWidth="1" />
<circle cx="200" cy="200" r={radius} fill="transparent" stroke="#e2e8f0" strokeWidth="2" />
{SPECIAL_ANGLES.map(a => {
const rTick = (a * Math.PI) / 180;
const x1 = 200 + (radius - 5) * Math.cos(rTick);
const y1 = 200 - (radius - 5) * Math.sin(rTick);
const x2 = 200 + radius * Math.cos(rTick);
const y2 = 200 - radius * Math.sin(rTick);
return <line key={a} x1={x1} y1={y1} x2={x2} y2={y2} stroke="#94a3b8" strokeWidth="1" />;
})}
<path d={`M 200 200 L ${px} 200 L ${px} ${py} Z`} fill="rgba(224, 231, 255, 0.4)" stroke="none" />
<line x1="200" y1="200" x2={px} y2={py} stroke="#1e293b" strokeWidth="2" />
<line x1="200" y1="200" x2={px} y2="200" stroke="#4f46e5" strokeWidth="3" />
<line x1={px} y1="200" x2={px} y2={py} stroke="#e11d48" strokeWidth="3" />
{angle > 0 && (
<path
d={`M 230 200 A 30 30 0 ${angle > 180 ? 1 : 0} 0 ${200 + 30*Math.cos(rad)} ${200 - 30*Math.sin(rad)}`}
fill="none" stroke="#0f172a" strokeWidth="1.5"
/>
)}
<circle cx={px} cy={py} r="8" fill="#0f172a" stroke="white" strokeWidth="2" className="shadow-sm" />
<circle cx={px} cy={py} r="20" fill="transparent" cursor="grab" />
<text x={200 + (px - 200)/2} y={200 + (y >= 0 ? 15 : -10)} textAnchor="middle" className="text-xs font-bold fill-indigo-600">cos</text>
<text x={px + (x >= 0 ? 10 : -10)} y={200 - (200 - py)/2} textAnchor={x >= 0 ? "start" : "end"} className="text-xs font-bold fill-rose-600">sin</text>
<g transform={`translate(${x >= 0 ? 280 : 40}, ${y >= 0 ? 40 : 360})`}>
<rect x="-10" y="-20" width="130" height="40" rx="8" fill="white" stroke="#e2e8f0" className="shadow-sm" />
<text x="55" y="5" textAnchor="middle" className="font-mono text-sm font-bold fill-slate-700">
({cosStr}, {sinStr})
</text>
</g>
</svg>
<div className="flex gap-4 mt-2">
<button
onClick={() => setSnap(!snap)}
className={`text-xs px-3 py-1 rounded-full font-bold border transition-colors ${snap ? 'bg-slate-800 text-white border-slate-800' : 'bg-white text-slate-500 border-slate-200'}`}
>
{snap ? "Snapping ON" : "Snapping OFF"}
</button>
</div>
</div>
<div className="flex-1 w-full space-y-6">
<div className="bg-slate-50 p-5 rounded-xl border border-slate-200">
<div className="flex justify-between items-start mb-4">
<div>
<h3 className="text-sm font-bold uppercase text-slate-500">Current Angle</h3>
<div className="flex items-baseline gap-3 mt-1">
<span className={`text-4xl font-mono font-bold ${getAngleColor()}`}>{Math.round(angle)}°</span>
<span className="text-2xl font-mono text-slate-400">=</span>
<span className="text-3xl font-mono font-bold text-slate-700">{getRadianLabel(angle)}</span>
<span className="text-sm text-slate-400 ml-1">rad</span>
</div>
</div>
</div>
<div className="space-y-2">
<p className="text-xs font-bold text-slate-400 uppercase">Common Angles</p>
<div className="flex flex-wrap gap-2">
{[0, 30, 45, 60, 90, 180, 270].map(a => (
<button
key={a}
onClick={() => setAngle(a)}
className={`w-10 h-10 rounded-lg text-sm font-bold transition-all ${
angle === a
? 'bg-indigo-600 text-white shadow-md scale-110'
: 'bg-white border border-slate-200 text-slate-600 hover:border-indigo-300 hover:text-indigo-600'
}`}
>
{a}°
</button>
))}
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="p-4 bg-indigo-50 border border-indigo-100 rounded-xl">
<div className="text-xs font-bold uppercase text-indigo-800 mb-1">Cosine (x)</div>
<div className="text-3xl font-mono font-bold text-indigo-900">{cosStr}</div>
<div className="text-xs text-indigo-400 mt-1 font-mono">adj / hyp</div>
</div>
<div className="p-4 bg-rose-50 border border-rose-100 rounded-xl">
<div className="text-xs font-bold uppercase text-rose-800 mb-1">Sine (y)</div>
<div className="text-3xl font-mono font-bold text-rose-900">{sinStr}</div>
<div className="text-xs text-rose-400 mt-1 font-mono">opp / hyp</div>
</div>
</div>
<div className="p-4 bg-amber-50 border border-amber-100 rounded-xl text-center">
<div className="text-xs font-bold uppercase text-amber-800 mb-1">Tangent (sin/cos)</div>
<div className="text-2xl font-mono font-bold text-amber-900">
{Math.abs(x) < 0.001 ? "Undefined" : getExactValue(y/x)}
</div>
</div>
<p className="text-xs text-slate-400 text-center">
Pro tip: On the SAT, memorize the values for 30°, 45°, and 60°!
</p>
</div>
</div>
);
};
export default UnitCircleWidget;

View File

@ -0,0 +1,71 @@
import React, { useState } from 'react';
import { ArrowRight } from 'lucide-react';
const UnitConversionWidget: React.FC = () => {
const [speed, setSpeed] = useState(60); // miles per hour
// Steps
const ftPerMile = 5280;
const secPerHour = 3600;
const ftPerHour = speed * ftPerMile;
const ftPerSec = ftPerHour / secPerHour;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="mb-8">
<label className="text-sm font-bold text-slate-500 uppercase">Speed (mph)</label>
<div className="flex items-center gap-4 mt-2">
<input
type="range" min="10" max="100" step="5" value={speed}
onChange={e => setSpeed(Number(e.target.value))}
className="flex-1 h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-amber-600"
/>
<span className="font-mono font-bold text-2xl text-slate-800 w-20 text-right">{speed}</span>
</div>
</div>
<div className="space-y-6">
{/* Step 1: Write initial */}
<div className="flex items-center gap-4 p-4 bg-slate-50 rounded-lg border border-slate-200 overflow-x-auto">
<div className="flex flex-col items-center">
<span className="font-bold text-lg text-slate-800">{speed} miles</span>
<div className="w-full h-0.5 bg-slate-800 my-1"></div>
<span className="font-bold text-lg text-slate-800">1 hour</span>
</div>
<span className="text-slate-400 font-bold">×</span>
<div className="flex flex-col items-center">
<span className="font-bold text-lg text-emerald-600">5280 feet</span>
<div className="w-full h-0.5 bg-emerald-600 my-1"></div>
<span className="font-bold text-lg text-rose-600 line-through decoration-2">1 mile</span>
</div>
<span className="text-slate-400 font-bold">×</span>
<div className="flex flex-col items-center">
<span className="font-bold text-lg text-slate-800 line-through decoration-2 decoration-rose-600">1 hour</span>
<div className="w-full h-0.5 bg-slate-800 my-1"></div>
<span className="font-bold text-lg text-emerald-600">3600 sec</span>
</div>
<ArrowRight className="w-6 h-6 text-slate-400 shrink-0" />
<div className="flex flex-col items-center bg-white px-4 py-2 rounded shadow-sm border border-emerald-200">
<span className="font-bold text-xl text-emerald-700">{ftPerSec.toFixed(1)} ft</span>
<div className="w-full h-0.5 bg-emerald-700 my-1"></div>
<span className="font-bold text-xl text-emerald-700">1 sec</span>
</div>
</div>
<div className="text-sm text-slate-500">
<p><strong className="text-rose-600">Red units</strong> cancel out (top and bottom).</p>
<p><strong className="text-emerald-600">Green units</strong> remain.</p>
</div>
</div>
</div>
);
};
export default UnitConversionWidget;

View File

@ -0,0 +1,378 @@
import React, { useState, useEffect, useRef } from 'react';
import {
ArrowLeft, User, Shield, Clock, BookOpen, Calculator, Award,
TrendingUp, CheckCircle2, Circle, Lock, Eye, EyeOff, AlertCircle,
Check, Sparkles,
} from 'lucide-react';
import { useAuth, UserRecord } from './auth/AuthContext';
import { useProgress } from './progress/ProgressContext';
import { useGoldCoins } from './practice/GoldCoinContext';
import { LESSONS, EBRW_LESSONS } from '../constants';
import Mascot from './Mascot';
// Animated count-up
function useCountUp(target: number, duration = 900) {
const [count, setCount] = useState(0);
const started = useRef(false);
useEffect(() => {
if (started.current) return;
started.current = true;
const startTime = performance.now();
const animate = (now: number) => {
const progress = Math.min((now - startTime) / duration, 1);
const eased = 1 - Math.pow(1 - progress, 2.5);
setCount(Math.round(eased * target));
if (progress < 1) requestAnimationFrame(animate);
};
requestAnimationFrame(animate);
}, [target, duration]);
return count;
}
interface UserDashboardProps {
onExit: () => void;
}
export default function UserDashboard({ onExit }: UserDashboardProps) {
const { username, role, getUserRecord, changePassword, updateDisplayName } = useAuth();
const { getSubjectStats, getLessonStatus } = useProgress();
const { totalCoins, state: coinState } = useGoldCoins();
const user = getUserRecord(username || '');
const mathStats = getSubjectStats('math');
const ebrwStats = getSubjectStats('ebrw');
// Account settings
const [currentPassword, setCurrentPassword] = useState('');
const [newPassword, setNewPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [showCurrentPw, setShowCurrentPw] = useState(false);
const [showNewPw, setShowNewPw] = useState(false);
const [pwMsg, setPwMsg] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
const [pwLoading, setPwLoading] = useState(false);
const [editName, setEditName] = useState(false);
const [nameInput, setNameInput] = useState(user?.displayName || '');
const [nameSaved, setNameSaved] = useState(false);
const animCoins = useCountUp(totalCoins, 1200);
// Count completed topics across all practice
const topicsAttempted = Object.keys(coinState.topicProgress).length;
// Calculate total accuracy
let totalAttempted = 0;
let totalCorrect = 0;
Object.values(coinState.topicProgress).forEach((tp: any) => {
(['easy', 'medium', 'hard'] as const).forEach(d => {
totalAttempted += tp[d]?.attempted || 0;
totalCorrect += tp[d]?.correct || 0;
});
});
const accuracy = totalAttempted > 0 ? Math.round((totalCorrect / totalAttempted) * 100) : 0;
const handleChangePassword = async (e: React.FormEvent) => {
e.preventDefault();
setPwMsg(null);
if (newPassword !== confirmPassword) {
setPwMsg({ type: 'error', text: 'New passwords do not match.' });
return;
}
setPwLoading(true);
const result = await changePassword(username || '', currentPassword, newPassword);
setPwLoading(false);
if (result.success) {
setPwMsg({ type: 'success', text: 'Password changed successfully!' });
setCurrentPassword('');
setNewPassword('');
setConfirmPassword('');
} else {
setPwMsg({ type: 'error', text: result.error || 'Failed to change password.' });
}
};
const handleSaveName = () => {
if (username && nameInput.trim()) {
updateDisplayName(username, nameInput.trim());
setEditName(false);
setNameSaved(true);
setTimeout(() => setNameSaved(false), 2000);
}
};
// Progress ring
function ProgressRing({ percent, size = 72, stroke = 6, color }: { percent: number; size?: number; stroke?: number; color: string }) {
const r = (size - stroke) / 2;
const circ = 2 * Math.PI * r;
const offset = circ - (percent / 100) * circ;
return (
<svg width={size} height={size} className="transform -rotate-90">
<circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="currentColor" strokeWidth={stroke} className="text-slate-100" />
<circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke={color} strokeWidth={stroke}
strokeDasharray={circ} strokeDashoffset={offset} strokeLinecap="round"
className="transition-all duration-1000 ease-out" />
<text x={size / 2} y={size / 2} textAnchor="middle" dominantBaseline="central"
className="text-sm font-bold fill-slate-800 transform rotate-90" style={{ transformOrigin: 'center' }}>
{percent}%
</text>
</svg>
);
}
function StatusIcon({ status }: { status: string }) {
if (status === 'completed') return <CheckCircle2 className="w-4 h-4 text-emerald-500" />;
if (status === 'in_progress') return <Circle className="w-4 h-4 text-blue-400" />;
return <Lock className="w-3.5 h-3.5 text-slate-300" />;
}
return (
<div className="min-h-screen bg-gradient-to-b from-white via-slate-50/50 to-white">
{/* Header */}
<header className="sticky top-0 z-40 glass-nav border-b border-slate-100">
<div className="max-w-5xl mx-auto px-6 h-14 flex items-center justify-between">
<button onClick={onExit} className="flex items-center gap-2 text-sm font-semibold text-slate-500 hover:text-slate-900 transition-colors">
<ArrowLeft className="w-4 h-4" /> Back to Home
</button>
<h1 className="text-sm font-bold text-slate-800">My Dashboard</h1>
<div className="w-20" />
</div>
</header>
<div className="max-w-5xl mx-auto px-6 py-10 space-y-10">
{/* ── Welcome Hero ── */}
<div className="relative bg-gradient-to-br from-cyan-50 via-white to-blue-50 rounded-2xl p-8 border border-cyan-100 overflow-hidden anim-fade-in-up">
<div className="absolute -top-2 -right-2 pointer-events-none select-none opacity-80">
<Mascot pose="waving" height={120} />
</div>
<div className="relative">
<div className="flex items-center gap-3 mb-3">
<div className="w-12 h-12 rounded-xl bg-cyan-100 flex items-center justify-center">
<User className="w-6 h-6 text-cyan-600" />
</div>
<div>
<div className="flex items-center gap-2">
{editName ? (
<div className="flex items-center gap-2">
<input value={nameInput} onChange={e => setNameInput(e.target.value)}
className="text-xl font-bold text-slate-900 bg-white border border-slate-200 rounded-lg px-2 py-0.5 focus:outline-none focus:ring-2 focus:ring-cyan-400 w-48"
autoFocus onKeyDown={e => e.key === 'Enter' && handleSaveName()} />
<button onClick={handleSaveName} className="text-xs font-bold text-cyan-600 hover:text-cyan-800">Save</button>
<button onClick={() => setEditName(false)} className="text-xs text-slate-400 hover:text-slate-600">Cancel</button>
</div>
) : (
<>
<h2 className="text-xl font-bold text-slate-900">{user?.displayName || username}</h2>
<button onClick={() => { setNameInput(user?.displayName || ''); setEditName(true); }}
className="text-xs text-cyan-500 hover:text-cyan-700 font-medium">edit</button>
{nameSaved && <span className="text-xs text-emerald-500 font-medium flex items-center gap-1"><Check className="w-3 h-3" /> Saved</span>}
</>
)}
</div>
<div className="flex items-center gap-2 mt-0.5">
<span className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[10px] font-bold uppercase tracking-widest ${
role === 'admin' ? 'bg-amber-100 text-amber-700' : 'bg-cyan-100 text-cyan-700'
}`}>
{role === 'admin' && <Shield className="w-3 h-3" />}
{role}
</span>
<span className="text-xs text-slate-400">@{username}</span>
</div>
</div>
</div>
{user?.lastLoginAt && (
<p className="text-xs text-slate-400 mt-2 flex items-center gap-1">
<Clock className="w-3 h-3" />
Last login: {new Date(user.lastLoginAt).toLocaleString()}
{user.lastLoginIp && user.lastLoginIp !== 'unknown' && <span className="ml-1">from {user.lastLoginIp}</span>}
</p>
)}
</div>
</div>
{/* ── Stats Overview ── */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 anim-fade-in-up stagger-1">
<div className="bg-white rounded-2xl p-5 border border-slate-200 card-lift text-center">
<p className="text-3xl font-bold text-slate-900 tabular-nums">{mathStats.completed + ebrwStats.completed}</p>
<p className="text-[10px] font-bold uppercase tracking-widest text-slate-400 mt-1">Lessons Done</p>
</div>
<div className="bg-white rounded-2xl p-5 border border-slate-200 card-lift text-center">
<p className="text-3xl font-bold text-amber-500 tabular-nums flex items-center justify-center gap-1">
<Award className="w-5 h-5" />{animCoins}
</p>
<p className="text-[10px] font-bold uppercase tracking-widest text-slate-400 mt-1">Gold Coins</p>
</div>
<div className="bg-white rounded-2xl p-5 border border-slate-200 card-lift text-center">
<p className="text-3xl font-bold text-emerald-500 tabular-nums">{accuracy}%</p>
<p className="text-[10px] font-bold uppercase tracking-widest text-slate-400 mt-1">Accuracy</p>
</div>
<div className="bg-white rounded-2xl p-5 border border-slate-200 card-lift text-center">
<p className="text-3xl font-bold text-blue-500 tabular-nums">{topicsAttempted}</p>
<p className="text-[10px] font-bold uppercase tracking-widest text-slate-400 mt-1">Topics Practiced</p>
</div>
</div>
{/* ── Lesson Progress ── */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 anim-fade-in-up stagger-2">
{/* Math */}
<div className="bg-white rounded-2xl p-6 border border-slate-200 card-lift">
<div className="flex items-center justify-between mb-5">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-blue-50 flex items-center justify-center">
<Calculator className="w-5 h-5 text-blue-500" />
</div>
<div>
<h3 className="font-bold text-slate-900">Mathematics</h3>
<p className="text-xs text-slate-400">{mathStats.completed}/{mathStats.total} lessons completed</p>
</div>
</div>
<ProgressRing percent={mathStats.percentComplete} color="#3b82f6" />
</div>
<div className="w-full h-2 bg-slate-100 rounded-full overflow-hidden mb-4">
<div className="h-full bg-blue-500 rounded-full transition-all duration-1000" style={{ width: `${mathStats.percentComplete}%` }} />
</div>
<div className="space-y-1 max-h-48 overflow-y-auto pr-1">
{LESSONS.map(l => (
<div key={l.id} className="flex items-center gap-2 py-1 text-xs">
<StatusIcon status={getLessonStatus(l.id, 'math')} />
<span className="text-slate-600 truncate">{l.title}</span>
</div>
))}
</div>
</div>
{/* EBRW */}
<div className="bg-white rounded-2xl p-6 border border-slate-200 card-lift">
<div className="flex items-center justify-between mb-5">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-purple-50 flex items-center justify-center">
<BookOpen className="w-5 h-5 text-purple-500" />
</div>
<div>
<h3 className="font-bold text-slate-900">Reading & Writing</h3>
<p className="text-xs text-slate-400">{ebrwStats.completed}/{ebrwStats.total} lessons completed</p>
</div>
</div>
<ProgressRing percent={ebrwStats.percentComplete} color="#a855f7" />
</div>
<div className="w-full h-2 bg-slate-100 rounded-full overflow-hidden mb-4">
<div className="h-full bg-purple-500 rounded-full transition-all duration-1000" style={{ width: `${ebrwStats.percentComplete}%` }} />
</div>
<div className="space-y-1 max-h-48 overflow-y-auto pr-1">
{EBRW_LESSONS.map(l => (
<div key={l.id} className="flex items-center gap-2 py-1 text-xs">
<StatusIcon status={getLessonStatus(l.id, 'ebrw')} />
<span className="text-slate-600 truncate">{l.title}</span>
</div>
))}
</div>
</div>
</div>
{/* ── Practice Performance ── */}
<div className="bg-white rounded-2xl p-6 border border-slate-200 anim-fade-in-up stagger-3">
<div className="flex items-center gap-3 mb-5">
<div className="w-10 h-10 rounded-xl bg-amber-50 flex items-center justify-center">
<TrendingUp className="w-5 h-5 text-amber-500" />
</div>
<div>
<h3 className="font-bold text-slate-900">Practice Performance</h3>
<p className="text-xs text-slate-400">{totalAttempted} questions attempted across {topicsAttempted} topics</p>
</div>
</div>
{topicsAttempted === 0 ? (
<div className="py-8 text-center text-slate-400 text-sm">
<Sparkles className="w-6 h-6 mx-auto mb-2 text-amber-300" />
No practice sessions yet. Start practicing to see your performance!
</div>
) : (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
{Object.entries(coinState.topicProgress).map(([topicId, tp]: [string, any]) => {
const easy = tp.easy || { attempted: 0, correct: 0 };
const medium = tp.medium || { attempted: 0, correct: 0 };
const hard = tp.hard || { attempted: 0, correct: 0 };
const total = easy.attempted + medium.attempted + hard.attempted;
const correct = easy.correct + medium.correct + hard.correct;
const acc = total > 0 ? Math.round((correct / total) * 100) : 0;
return (
<div key={topicId} className="border border-slate-100 rounded-xl p-3 hover:border-slate-200 transition-colors">
<p className="text-xs font-semibold text-slate-700 truncate mb-2">{topicId}</p>
<div className="flex items-center justify-between text-[10px] text-slate-400 mb-1">
<span>{correct}/{total} correct</span>
<span className={`font-bold ${acc >= 70 ? 'text-emerald-500' : acc >= 40 ? 'text-amber-500' : 'text-rose-500'}`}>{acc}%</span>
</div>
<div className="w-full h-1.5 bg-slate-100 rounded-full overflow-hidden">
<div className={`h-full rounded-full ${acc >= 70 ? 'bg-emerald-400' : acc >= 40 ? 'bg-amber-400' : 'bg-rose-400'}`} style={{ width: `${acc}%` }} />
</div>
<div className="flex gap-3 mt-2 text-[10px] text-slate-400">
<span>E: {easy.correct}/{easy.attempted}</span>
<span>M: {medium.correct}/{medium.attempted}</span>
<span>H: {hard.correct}/{hard.attempted}</span>
</div>
</div>
);
})}
</div>
)}
</div>
{/* ── Account Settings ── */}
<div className="bg-white rounded-2xl p-6 border border-slate-200 anim-fade-in-up stagger-4">
<div className="flex items-center gap-3 mb-5">
<div className="w-10 h-10 rounded-xl bg-slate-100 flex items-center justify-center">
<Lock className="w-5 h-5 text-slate-500" />
</div>
<div>
<h3 className="font-bold text-slate-900">Change Password</h3>
<p className="text-xs text-slate-400">Update your account password</p>
</div>
</div>
<form onSubmit={handleChangePassword} className="max-w-sm space-y-3">
{pwMsg && (
<div className={`flex items-center gap-2 p-3 rounded-xl text-sm ${
pwMsg.type === 'success' ? 'bg-emerald-50 border border-emerald-200 text-emerald-700' : 'bg-rose-50 border border-rose-200 text-rose-700'
}`}>
{pwMsg.type === 'success' ? <Check className="w-4 h-4 shrink-0" /> : <AlertCircle className="w-4 h-4 shrink-0" />}
{pwMsg.text}
</div>
)}
<div className="relative">
<label className="block text-xs font-semibold text-slate-600 mb-1">Current Password</label>
<input type={showCurrentPw ? 'text' : 'password'} value={currentPassword} onChange={e => setCurrentPassword(e.target.value)}
className="w-full px-3 py-2 pr-9 text-sm border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-cyan-400" required />
<button type="button" onClick={() => setShowCurrentPw(!showCurrentPw)} className="absolute right-3 top-7 text-slate-400 hover:text-slate-600">
{showCurrentPw ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
<div className="relative">
<label className="block text-xs font-semibold text-slate-600 mb-1">New Password</label>
<input type={showNewPw ? 'text' : 'password'} value={newPassword} onChange={e => setNewPassword(e.target.value)}
className="w-full px-3 py-2 pr-9 text-sm border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-cyan-400" required minLength={4} />
<button type="button" onClick={() => setShowNewPw(!showNewPw)} className="absolute right-3 top-7 text-slate-400 hover:text-slate-600">
{showNewPw ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
<div>
<label className="block text-xs font-semibold text-slate-600 mb-1">Confirm New Password</label>
<input type="password" value={confirmPassword} onChange={e => setConfirmPassword(e.target.value)}
className="w-full px-3 py-2 text-sm border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-cyan-400" required minLength={4} />
</div>
<button type="submit" disabled={pwLoading}
className="px-5 py-2 bg-slate-900 text-white text-sm font-bold rounded-xl hover:bg-slate-700 transition-all btn-primary disabled:opacity-50">
{pwLoading ? 'Changing...' : 'Change Password'}
</button>
</form>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,670 @@
import { type PracticeQuestion } from "../../types/lesson";
export const AREA_VOL_EASY: PracticeQuestion[] = [
{
id: "02b02213",
type: "mcq",
questionHtml:
"What is the perimeter, in inches, of a rectangle with a length of <strong>4</strong> inches and a width of <strong>9</strong> inches?",
choices: [
{ label: "A", text: "<strong>13</strong>" },
{ label: "B", text: "<strong>17</strong>" },
{ label: "C", text: "<strong>22</strong>" },
{ label: "D", text: "<strong>26</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The perimeter of a figure is equal to the sum of the measurements of the sides of the figure. Its given that the rectangle has a length of <strong>4</strong> inches and a width of <strong>9</strong> inches. Since a rectangle has <strong>4</strong> sides, of which opposite sides are parallel and equal, it follows that the rectangle has two sides with a length of <strong>4</strong> inches and two sides with a width of <strong>9</strong> inches. Therefore, the perimeter of this rectangle is <strong>4 + 4 + 9 + 9</strong>, or <strong>26</strong> inches.<br>Choice A is incorrect. This is the sum, in inches, of the length and the width of the rectangle.<br>Choice B is incorrect. This is the sum, in inches, of the two lengths and the width of the rectangle.<br>Choice C is incorrect. This is the sum, in inches, of the length and the two widths of the rectangle.",
hasFigure: false,
},
{
id: "0837c3b9",
type: "mcq",
questionHtml:
"Triangle ABC and triangle DEF are similar triangles, where <strong>A B</strong> and <strong>D E</strong> are corresponding sides. If <strong>the length of D E = 2 · the length of A B</strong> and the perimeter of triangle ABC is 20, what is the perimeter of triangle DEF ?",
choices: [
{ label: "A", text: "10" },
{ label: "B", text: "40" },
{ label: "C", text: "80" },
{ label: "D", text: "120" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Since triangles ABC and DEF are similar and <strong>the length of side D E = 2 · the length of side A B</strong>, the length of each side of triangle DEF is two times the length of its corresponding side in triangle ABC. Therefore, the perimeter of triangle DEF is two times the perimeter of triangle ABC. Since the perimeter of triangle ABC is 20, the perimeter of triangle DEF is 40.Choice A is incorrect. This is half, not two times, the perimeter of triangle ABC. Choice C is incorrect. This is two times the perimeter of triangle DEF rather than two times the perimeter of triangle ABC. Choice D is incorrect. This is six times, not two times, the perimeter of triangle ABC.",
hasFigure: false,
},
{
id: "165c30c4",
type: "spr",
questionHtml:
"A rectangle has a length of <strong>64</strong> inches and a width of <strong>32</strong> inches. What is the area, in square inches, of the rectangle?",
choices: [],
correctAnswer: "2048",
explanation:
"The correct answer is <strong>2, 048</strong>. The area <strong>A</strong>, in square inches, of a rectangle is equal to the product of its length <strong>script l</strong>, in inches, and its width <strong>w</strong>, in inches, or <strong>A = script l w</strong>. It's given that the rectangle has a length of <strong>64</strong> inches and a width of <strong>32</strong> inches. Substituting <strong>64</strong> for <strong>script l</strong> and <strong>32</strong> for <strong>w</strong> in the equation <strong>A = script l w</strong> yields <strong>A = (64) (32)</strong>, or <strong>A = 2, 048</strong>. Therefore, the area, in square inches, of the rectangle is <strong>2, 048</strong>.",
hasFigure: false,
},
{
id: "29e9b28c",
type: "mcq",
questionHtml:
"The lengths of the sides are x, y, and z.<br>A note indicates the figure is not drawn to scale.<br><br> <br>The triangle shown has a perimeter of <strong>22</strong> units. If <strong>x = 9</strong> units and <strong>y = 7</strong> units, what is the value of <strong>z</strong>, in units?",
choices: [
{ label: "A", text: "<strong>6</strong>" },
{ label: "B", text: "<strong>7</strong>" },
{ label: "C", text: "<strong>9</strong>" },
{ label: "D", text: "<strong>16</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The perimeter of a triangle is the sum of the lengths of its three sides. The triangle shown has side lengths <strong>x</strong>, <strong>y</strong>, and <strong>z</strong>. It's given that the triangle has a perimeter of <strong>22</strong> units. Therefore, <strong>x + y + z = 22</strong>. If <strong>x = 9</strong> units and <strong>y = 7</strong> units, the value of <strong>z</strong>, in units, can be found by substituting <strong>9</strong> for <strong>x</strong> and <strong>7</strong> for <strong>y</strong> in the equation <strong>x + y + z = 22</strong>, which yields <strong>9 + 7 + z = 22</strong>, or <strong>16 + z = 22</strong>. Subtracting <strong>16</strong> from both sides of this equation yields <strong>z = 6</strong>. Therefore, if <strong>x = 9</strong> units and <strong>y = 7</strong> units, the value of <strong>z</strong>, in units, is <strong>6</strong>.<br>Choice B is incorrect. This is the value of <strong>y</strong>, in units, not the value of <strong>z</strong>, in units.<br>Choice C is incorrect. This is the value of <strong>x</strong>, in units, not the value of <strong>z</strong>, in units.<br>Choice D is incorrect. This is the value of <strong>x + y</strong>, in units, not the value of <strong>z</strong>, in units.",
hasFigure: true,
figureUrl: "/practice-images/29e9b28c_svg1.svg",
},
{
id: "3453aafc",
type: "mcq",
questionHtml:
"What is the area, in square centimeters, of a rectangle with a length of <strong>36</strong> centimeters and a width of <strong>34</strong> centimeters?",
choices: [
{ label: "A", text: "<strong>70</strong>" },
{ label: "B", text: "<strong>140</strong>" },
{ label: "C", text: "<strong>1, 156</strong>" },
{ label: "D", text: "<strong>1, 224</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The area <strong>A</strong>, in square centimeters, of a rectangle can be found using the formula <strong>A = script l w</strong>, where <strong>script l</strong> is the length, in centimeters, of the rectangle and <strong>w</strong> is its width, in centimeters. It's given that the rectangle has a length of <strong>36</strong> centimeters and a width of <strong>34</strong> centimeters. Substituting <strong>36</strong> for <strong>script l</strong> and <strong>34</strong> for <strong>w</strong> in the formula <strong>A = script l w</strong> yields <strong>A = 36 (34)</strong>, or <strong>A = 1, 224</strong>. Therefore, the area, in square centimeters, of this rectangle is <strong>1, 224</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect. This is the perimeter, in centimeters, not the area, in square centimeters, of the rectangle.<br>Choice C is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "4420e500",
type: "mcq",
questionHtml:
"What is the area of a rectangle with a length of <strong>4 centimeters (cm)</strong> and a width of <strong>2 cm</strong>?",
choices: [
{ label: "A", text: "<strong>6 cm²</strong>" },
{ label: "B", text: "<strong>8 cm²</strong>" },
{ label: "C", text: "<strong>12 cm²</strong>" },
{ label: "D", text: "<strong>36 cm²</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The area of a rectangle with length <strong>script l</strong> and width <strong>w</strong> can be found using the formula <strong>A = script l w</strong>. Its given that the rectangle has a length of <strong>4 cm</strong> and a width of <strong>2 cm</strong>. Therefore, the area of this rectangle is <strong>(4 cm) (2 cm)</strong>, or <strong>8 cm²</strong>.<br>Choice A is incorrect. This is the sum, <strong>in cm</strong>, of the length and width of the rectangle, not the area, <strong>in cm²</strong>.<br>Choice C is incorrect. This is the perimeter, <strong>in cm</strong>, of the rectangle, not the area, <strong>in cm²</strong>.<br>Choice D is incorrect. This is the sum of the length and width of the rectangle squared, not the area.",
hasFigure: false,
},
{
id: "5252e606",
type: "mcq",
questionHtml:
"The side length of a square is <strong>55 centimeters (cm)</strong>. What is the area, <strong>in cm²</strong>, of the square?",
choices: [
{ label: "A", text: "<strong>110</strong>" },
{ label: "B", text: "<strong>220</strong>" },
{ label: "C", text: "<strong>3, 025</strong>" },
{ label: "D", text: "<strong>12, 100</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The area <strong>A</strong>, <strong>in square centimeters (cm²)</strong>, of a square with side length <strong>s</strong>, <strong>in cm</strong>, is given by the formula <strong>A = s²</strong>. Its given that the square has a side length of <strong>55 cm</strong>. Substituting <strong>55</strong> for <strong>s</strong> in the formula <strong>A = s²</strong> yields <strong>A = 55²</strong>, or <strong>A = 3, 025</strong>. Therefore, the area, <strong>in cm²</strong>, of the square is <strong>3, 025</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect. This is the perimeter, <strong>in cm</strong>, of the square, not its area, <strong>in cm²</strong>.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "575f1e12",
type: "spr",
questionHtml:
"What is the area, in square centimeters, of a rectangle with a length of <strong>34 centimeters (cm)</strong> and a width of <strong>29 cm</strong>?",
choices: [],
correctAnswer: "986",
explanation:
"The correct answer is <strong>986</strong>. The area, <strong>A</strong>, of a rectangle is given by <strong>A = script l w</strong>, where <strong>script l</strong> is the length of the rectangle and <strong>w</strong> is its width. Its given that the length of the rectangle is <strong>34</strong> centimeters (cm) and the width is <strong>29</strong> cm. Substituting <strong>34</strong> for <strong>script l</strong> and <strong>29</strong> for <strong>w</strong> in the equation <strong>A = script l w</strong> yields <strong>A = (34) (29)</strong>, or <strong>A = 986</strong>. Therefore, the area, in square centimeters, of this rectangle is <strong>986</strong>.",
hasFigure: false,
},
{
id: "59cb654c",
type: "mcq",
questionHtml:
"The area of a square is <strong>64</strong> square inches. What is the side length, in inches, of this square?",
choices: [
{ label: "A", text: "<strong>8</strong>" },
{ label: "B", text: "<strong>16</strong>" },
{ label: "C", text: "<strong>64</strong>" },
{ label: "D", text: "<strong>128</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. It's given that the area of a square is <strong>64</strong> square inches. The area <strong>A</strong>, in square inches, of a square is given by the formula <strong>A = s²</strong>, where <strong>s</strong> is the side length, in inches, of the square. Substituting <strong>64</strong> for <strong>A</strong> in this formula yields <strong>64 = s²</strong>. Taking the positive square root of both sides of this equation yields <strong>8 = s</strong>. Thus, the side length, in inches, of this square is <strong>8</strong>.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect. This is the area, in square inches, of the square, not the side length, in inches, of the square.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "76670c80",
type: "spr",
questionHtml:
"Each side of a square has a length of <strong>45</strong>. What is the perimeter of this square?",
choices: [],
correctAnswer: "180",
explanation:
"The correct answer is <strong>180</strong>. The perimeter of a polygon is equal to the sum of the lengths of the sides of the polygon. Its given that each side of the square has a length of <strong>45</strong>. Since a square is a polygon with <strong>4</strong> sides, the perimeter of this square is <strong>45 + 45 + 45 + 45</strong>, or <strong>180</strong>.",
hasFigure: false,
},
{
id: "c88183f7",
type: "mcq",
questionHtml:
"A rectangle has a length of <strong>13</strong> and a width of <strong>6</strong>. What is the perimeter of the rectangle?",
choices: [
{ label: "A", text: "<strong>12</strong>" },
{ label: "B", text: "<strong>26</strong>" },
{ label: "C", text: "<strong>38</strong>" },
{ label: "D", text: "<strong>52</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The perimeter of a quadrilateral is the sum of the lengths of its four sides. It's given that the rectangle has a length of <strong>13</strong> and a width of <strong>6</strong>. It follows that the rectangle has two sides with length <strong>13</strong> and two sides with length <strong>6</strong>. Therefore, the perimeter of the rectangle is <strong>13 + 13 + 6 + 6</strong>, or <strong>38</strong>.<br>Choice A is incorrect. This is the sum of the lengths of the two sides with length <strong>6</strong>, not the sum of the lengths of all four sides of the rectangle.<br>Choice B is incorrect. This is the sum of the lengths of the two sides with length <strong>13</strong>, not the sum of the lengths of all four sides of the rectangle.<br>Choice D is incorrect. This is the perimeter of a rectangle that has four sides with length <strong>13</strong>, not two sides with length <strong>13</strong> and two sides with length <strong>6</strong>.",
hasFigure: false,
},
{
id: "d0b6d927",
type: "mcq",
questionHtml:
"A rectangle has an area of <strong>63</strong> square meters and a length of <strong>9</strong> meters. What is the width, in meters, of the rectangle?",
choices: [
{ label: "A", text: "<strong>7</strong>" },
{ label: "B", text: "<strong>54</strong>" },
{ label: "C", text: "<strong>81</strong>" },
{ label: "D", text: "<strong>567</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The area <strong>A</strong>, in square meters, of a rectangle is the product of its length <strong>script l</strong>, in meters, and its width <strong>w</strong>, in meters; thus, <strong>A = script l w</strong>. It's given that a rectangle has an area of <strong>63</strong> square meters and a length of <strong>9</strong> meters. Substituting <strong>63</strong> for <strong>A</strong> and <strong>9</strong> for <strong>script l</strong> in the equation <strong>A = script l w</strong> yields <strong>63 = 9 w</strong>. Dividing both sides of this equation by <strong>9</strong> yields <strong>7 = w</strong>. Therefore, the width, in meters, of the rectangle is <strong>7</strong>.<br>Choice B is incorrect. This is the difference between the area, in square meters, and the length, in meters, of the rectangle, not the width, in meters, of the rectangle.<br>Choice C is incorrect. This is the square of the length, in meters, not the width, in meters, of the rectangle.<br>Choice D is incorrect. This is the product of the area, in square meters, and the length, in meters, of the rectangle, not the width, in meters, of the rectangle.",
hasFigure: false,
},
{
id: "d2047497",
type: "mcq",
questionHtml:
"What is the area of a rectangle with a length of <strong>17 centimeters (cm)</strong> and a width of <strong>7 cm</strong>?",
choices: [
{ label: "A", text: "<strong>24 cm²</strong>" },
{ label: "B", text: "<strong>48 cm²</strong>" },
{ label: "C", text: "<strong>119 cm²</strong>" },
{ label: "D", text: "<strong>576 cm²</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The area of a rectangle with length <strong>l</strong> and width <strong>w</strong> can be found using the formula <strong>A = l w</strong>. Its given that the rectangle has a length of <strong>17 cm</strong> and a width of <strong>7 cm</strong>. Therefore, the area of this rectangle is <strong>A = 17 (7)</strong>, or <strong>119 cm²</strong>.<br>Choice A is incorrect. This is the sum of the length and width of the rectangle, not the area.<br>Choice B is incorrect. This is the perimeter of the rectangle, not the area.<br>Choice D is incorrect. This is the sum of the length and width of the rectangle squared, not the area.",
hasFigure: false,
},
{
id: "d683a9cc",
type: "mcq",
questionHtml:
"The figure shows the lengths, in centimeters (cm), of the edges of a right rectangular prism. The volume V of a right rectangular prism is <strong>l w h</strong>, where <strong>l</strong> is the length of the prism, w is the width of the prism, and h is the height of the prism. What is the volume, in cubic centimeters, of the prism?",
choices: [
{ label: "A", text: "36" },
{ label: "B", text: "24" },
{ label: "C", text: "12" },
{ label: "D", text: "11" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that the volume of a right rectangular prism is <strong>l w h</strong>. The prism shown has a length of 6 cm, a width of 2 cm, and a height of 3 cm. Thus, <strong>l w h = 6 · 2 · 3</strong>, or 36 cubic centimeters.Choice B is incorrect. This is the volume of a rectangular prism with edge lengths of 6, 2, and 2. Choice C is incorrect and may result from only finding the product of the length and width of the base of the prism. Choice D is incorrect and may result from finding the sum, not the product, of the edge lengths of the prism.",
hasFigure: true,
figureUrl: "/practice-images/d683a9cc_img1.png",
},
{
id: "f60bb551",
type: "mcq",
questionHtml:
"The area of a rectangle is <strong>630</strong> square inches. The length of the rectangle is <strong>70</strong> inches. What is the width, in inches, of this rectangle?",
choices: [
{ label: "A", text: "<strong>9</strong>" },
{ label: "B", text: "<strong>70</strong>" },
{ label: "C", text: "<strong>315</strong>" },
{ label: "D", text: "<strong>560</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The area <strong>A</strong>, in square inches, of a rectangle is the product of its length <strong>script l</strong>, in inches, and its width <strong>w</strong>, in inches; thus, <strong>A = script l w</strong>. It's given that the area of a rectangle is <strong>630</strong> square inches and the length of the rectangle is <strong>70</strong> inches. Substituting <strong>630</strong> for <strong>A</strong> and <strong>70</strong> for <strong>script l</strong> in the equation <strong>A = script l w</strong> yields <strong>630 = 70 w</strong>. Dividing both sides of this equation by <strong>70</strong> yields <strong>9 = w</strong>. Therefore, the width, in inches, of this rectangle is <strong>9</strong>.<br>Choice B is incorrect. This is the length, not the width, in inches, of the rectangle.<br>Choice C is incorrect. This is half the area, in square inches, not the width, in inches, of the rectangle.<br>Choice D is incorrect. This is the difference between the area, in square inches, and the length, in inches, of the rectangle, not the width, in inches, of the rectangle.",
hasFigure: false,
},
];
export const AREA_VOL_MEDIUM: PracticeQuestion[] = [
{
id: "08b7a3f5",
type: "spr",
questionHtml:
"A triangular prism has a height of <strong>8 centimeters (cm)</strong> and a volume of <strong>216 cm³</strong>. What is the area, <strong>in cm²</strong>, of the base of the prism? (The volume of a triangular prism is equal to <strong>B h</strong>, where <strong>B</strong> is the area of the base and <strong>h</strong> is the height of the prism.)",
choices: [],
correctAnswer: "27",
explanation:
"The correct answer is <strong>27</strong>. It's given that a triangular prism has a volume of <strong>216 cubic centimeters (cm³)</strong> and the volume of a triangular prism is equal to <strong>B h</strong>, where <strong>B</strong> is the area of the base and <strong>h</strong> is the height of the prism. Therefore, <strong>216 = B h</strong>. It's also given that the triangular prism has a height of <strong>8 cm</strong>. Therefore, <strong>h = 8</strong>. Substituting <strong>8</strong> for <strong>h</strong> in the equation <strong>216 = B h</strong> yields <strong>216 = B (8)</strong>. Dividing both sides of this equation by <strong>8</strong> yields <strong>27 = B</strong>. Therefore, the area, <strong>in cm²</strong>, of the base of the prism is <strong>27</strong>.",
hasFigure: false,
},
{
id: "151eda3c",
type: "mcq",
questionHtml:
"A manufacturing company produces two sizes of cylindrical containers that each have a height of 50 centimeters. The radius of container A is 16 centimeters, and the radius of container B is 25% longer than the radius of container A. What is the volume, in cubic centimeters, of container B?",
choices: [
{ label: "A", text: "<strong>16, 000 π</strong>" },
{ label: "B", text: "<strong>20, 000 π</strong>" },
{ label: "C", text: "<strong>25, 000 π</strong>" },
{ label: "D", text: "<strong>31, 250 π</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. If the radius of container A is 16 centimeters and the radius of container B is 25% longer than the radius of container A, then the radius of container B is <strong>16 + 0 . 2 5 · 16 = 20</strong> centimeters. The volume of a cylinder is <strong>π · r² · h</strong>, where r is the radius of the cylinder and h is its height. Substituting <strong>r = 20</strong> and <strong>h = 50</strong> into <strong>π · r² · h</strong> yields that the volume of cylinder B is <strong>π · (20, ), ² · 50 = 20, 000 π</strong> cubic centimeters.Choice A is incorrect and may result from multiplying the radius of cylinder B by the radius of cylinder A rather than squaring the radius of cylinder B. Choice C is incorrect and may result from multiplying the radius of cylinder B by 25 rather than squaring it. Choice D is incorrect and may result from taking the radius of cylinder B to be 25 centimeters rather than 20 centimeters.",
hasFigure: false,
},
{
id: "1f0b582e",
type: "mcq",
questionHtml:
"Square X has a side length of <strong>12</strong> centimeters. The perimeter of square Y is <strong>2</strong> times the perimeter of square X. What is the length, in centimeters, of one side of square Y?",
choices: [
{ label: "A", text: "<strong>6</strong>" },
{ label: "B", text: "<strong>10</strong>" },
{ label: "C", text: "<strong>14</strong>" },
{ label: "D", text: "<strong>24</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The perimeter, <strong>P</strong>, of a square can be found using the formula <strong>P = 4 s</strong>, where <strong>s</strong> is the length of each side of the square. It's given that square X has a side length of <strong>12</strong> centimeters. Substituting <strong>12</strong> for <strong>s</strong> in the formula for the perimeter of a square yields <strong>P = 4 (12)</strong>, or <strong>P = 48</strong>. Therefore, the perimeter of square X is <strong>48</strong> centimeters. Its also given that the perimeter of square Y is <strong>2</strong> times the perimeter of square X. Therefore, the perimeter of square Y is <strong>2 (48)</strong>, or <strong>96</strong>, centimeters. Substituting <strong>96</strong> for <strong>P</strong> in the formula <strong>P = 4 s</strong> gives <strong>96 = 4 s</strong>. Dividing both sides of this equation by <strong>4</strong> gives <strong>24 = s</strong>. Therefore, the length of one side of square Y is <strong>24</strong> centimeters.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "37dde49f",
type: "mcq",
questionHtml:
"<strong>The figure presents a cylindrical shape with a circular base and a larger circular top. The diameter of the circular base is labeled “k over 2, ” the diameter of the circular top is labeled “k, ” and the height is labeled “k.” The volume of the figure = the fraction with numerator 7 π k³, and denominator 48</strong>The glass pictured above can hold a maximum volume of 473 cubic centimeters, which is approximately 16 fluid ounces. What is the value of k, in centimeters?",
choices: [
{ label: "A", text: "2.52" },
{ label: "B", text: "7.67" },
{ label: "C", text: "7.79" },
{ label: "D", text: "10.11" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Using the volume formula <strong>V = the fraction with numerator 7 π · k³, and denominator 48</strong> and the given information that the volume of the glass is 473 cubic centimeters, the value of k can be found as follows:<br> <strong>473 = the fraction with numerator 7 π · k³, and denominator 48</strong><br><br> <strong>k³ = the fraction with numerator 473 · 48, and denominator 7 π, end fraction</strong><br><br> <strong>k = the cube root of the fraction with numerator 473 · 48, and denominator 7 π, end fraction, end root, which is ≈ 10 . 1 0 6 9 0</strong><br>Therefore, the value of k is approximately 10.11 centimeters.<br>Choices A, B, and C are incorrect. Substituting the values of k from these choices in the formula results in volumes of approximately 7 cubic centimeters, 207 cubic centimeters, and 217 cubic centimeters, respectively, all of which contradict the given information that the volume of the glass is 473 cubic centimeters.",
hasFigure: true,
figureUrl: "/practice-images/37dde49f_img1.png",
},
{
id: "38517165",
type: "spr",
questionHtml:
"A circle has a circumference of <strong>31 π</strong> centimeters. What is the diameter, in centimeters, of the circle?",
choices: [],
correctAnswer: "31",
explanation:
"The correct answer is <strong>31</strong>. The circumference of a circle is equal to <strong>2 π r</strong> centimeters, where <strong>r</strong> represents the radius, in centimeters, of the circle, and the diameter of the circle is equal to <strong>2 r</strong> centimeters. It's given that a circle has a circumference of <strong>31 π</strong> centimeters. Therefore, <strong>31 π = 2 π r</strong>. Dividing both sides of this equation by <strong>π</strong> yields <strong>31 = 2 r</strong>. Since the diameter of the circle is equal to <strong>2 r</strong> centimeters, it follows that the diameter, in centimeters, of the circle is <strong>31</strong>.",
hasFigure: false,
},
{
id: "5afbdc8e",
type: "mcq",
questionHtml:
"What is the length of one side of a square that has the same area as a circle with radius 2 ?",
choices: [
{ label: "A", text: "2" },
{ label: "B", text: "<strong>the √ 2 π, end root</strong>" },
{ label: "C", text: "<strong>2 · the √ π</strong>" },
{ label: "D", text: "<strong>2 π</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The area A of a circle with radius r is given by the formula <strong>A = π · r²</strong>. Thus, a circle with radius 2 has area <strong>π · 2²</strong>, which can be rewritten as <strong>4 π</strong>. The area of a square with side length s is given by the formula <strong>A = s²</strong>. Thus, if a square has the same area as a circle with radius 2, then <strong>s² = 4 π</strong>. Since the side length of a square must be a positive number, taking the square root of both sides of <strong>s² = 4 π</strong> gives <strong>s = the √ 4 π, end root</strong>. Using the properties of square roots, <strong>the √ 4 π, end root</strong> can be rewritten as <strong>(the √ 4, ) · (the √ π, )</strong>, which is equivalent to <strong>2 · the √ π</strong>. Therefore, <strong>s = 2 · the √ π</strong>.Choice A is incorrect. The side length of the square isnt equal to the radius of the circle. Choices B and D are incorrect and may result from incorrectly simplifying the expression <strong>the √ 4 π, end root</strong>.",
hasFigure: false,
},
{
id: "a2e76b60",
type: "mcq",
questionHtml:
"A cylindrical can containing pieces of fruit is filled to the top with syrup before being sealed. The base of the can has an area of <strong>75 centimeters²</strong>, and the height of the can is 10 cm. If <strong>110 centimeters³</strong> of syrup is needed to fill the can to the top, which of the following is closest to the total volume of the pieces of fruit in the can?",
choices: [
{ label: "A", text: "<strong>7 . 5 centimeters³</strong>" },
{ label: "B", text: "<strong>185 centimeters³</strong>" },
{ label: "C", text: "<strong>640 centimeters³</strong>" },
{ label: "D", text: "<strong>750 centimeters³</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The total volume of the cylindrical can is found by multiplying the area of the base of the can, <strong>75 square centimeters</strong>, by the height of the can, 10 cm, which yields <strong>750 cubic centimeters</strong>. If the syrup needed to fill the can has a volume of <strong>110 cubic centimeters</strong>, then the remaining volume for the pieces of<br><br>fruit is <strong>750 110 = 640 cubic centimeters</strong>.Choice A is incorrect because if the fruit had a volume of <strong>7 . 5 cubic centimeters</strong>, there would be <strong>750 7 . 5 = 742 . 5 cubic centimeters</strong> of syrup needed to fill the can to the top. Choice B is incorrect because if the fruit had a volume of <strong>185 cubic centimeters</strong>, there would be <strong>750 185 = 565 cubic centimeters</strong> of syrup needed to fill the can to the top. Choice D is incorrect because it is the total volume of the can, not just of the pieces of fruit.",
hasFigure: false,
},
{
id: "c0586eb5",
type: "mcq",
questionHtml:
"A cylinder has a diameter of <strong>8</strong> inches and a height of <strong>12</strong> inches. What is the volume, in cubic inches, of the cylinder?",
choices: [
{ label: "A", text: "<strong>16 π</strong>" },
{ label: "B", text: "<strong>96 π</strong>" },
{ label: "C", text: "<strong>192 π</strong>" },
{ label: "D", text: "<strong>768 π</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The base of a cylinder is a circle with a diameter equal to the diameter of the cylinder. The volume, <strong>V</strong>, of a cylinder can be found by multiplying the area of the circular base, <strong>A</strong>, by the height of the cylinder, <strong>h</strong>, or <strong>V = A h</strong>. The area of a circle can be found using the formula <strong>A = π r²</strong>, where <strong>r</strong> is the radius of the circle. Its given that the diameter of the cylinder is <strong>8</strong> inches. Thus, the radius of this circle is <strong>4</strong> inches. Therefore, the area of the circular base of the cylinder is <strong>A = π (4)²</strong>, or <strong>16 π</strong> square inches. Its given that the height <strong>h</strong> of the cylinder is <strong>12</strong> inches. Substituting <strong>16 π</strong> for <strong>A</strong> and <strong>12</strong> for <strong>h</strong> in the formula <strong>V = A h</strong> gives <strong>V = 16 π (12)</strong>, or <strong>192 π</strong> cubic inches.<br>Choice A is incorrect. This is the area of the circular base of the cylinder.<br>Choice B is incorrect and may result from using <strong>8</strong>, instead of <strong>16</strong>, as the value of <strong>r²</strong> in the formula for the area of a circle.<br>Choice D is incorrect and may result from using <strong>8</strong>, instead of <strong>4</strong>, for the radius of the circular base.",
hasFigure: false,
},
{
id: "cf53cb56",
type: "mcq",
questionHtml:
"In the xy-plane shown, square ABCD has its diagonals on the x- and y-axes. What is the area, in square units, of the square?",
choices: [
{ label: "A", text: "20" },
{ label: "B", text: "25" },
{ label: "C", text: "50" },
{ label: "D", text: "100" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The two diagonals of square ABCD divide the square into 4 congruent right triangles, where each triangle has a vertex at the origin of the graph shown. The formula for the area of a triangle is <strong>A = one half · b h</strong>, where b is the base length of the triangle and h is the height of the triangle. Each of the 4 congruent right triangles has a height of 5 units and a base length of 5 units. Therefore, the area of each triangle is <strong>A = one half · 5 · 5</strong>, or 12.5 square units. Since the 4 right triangles are congruent, the area of each is <strong>one fourth</strong> of the area of square ABCD. It follows that the area of the square ABCD is equal to <strong>4 · 12 . 5</strong>, or 50 square units.Choices A and D are incorrect and may result from using 5 or 25, respectively, as the area of one of the 4 congruent right triangles formed by diagonals of square ABCD. However, the area of these triangles is 12.5. Choice B is incorrect and may result from using 5 as the length of one side of square ABCD. However, the length of a side of square ABCD is <strong>5 · the √ 2</strong>.",
hasFigure: true,
figureUrl: "/practice-images/cf53cb56_img1.png",
},
{
id: "e336a1d2",
type: "mcq",
questionHtml:
"A cube has an edge length of <strong>41</strong> inches. What is the volume, in cubic inches, of the cube?",
choices: [
{ label: "A", text: "<strong>164</strong>" },
{ label: "B", text: "<strong>1, 681</strong>" },
{ label: "C", text: "<strong>10, 086</strong>" },
{ label: "D", text: "<strong>68, 921</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The volume, <strong>V</strong>, of a cube can be found using the formula <strong>V = s³</strong>, where <strong>s</strong> is the edge length of the cube. It's given that a cube has an edge length of <strong>41</strong> inches. Substituting <strong>41</strong> inches for <strong>s</strong> in this equation yields <strong>V = 41³</strong> cubic inches, or <strong>V = 68, 921</strong> cubic inches. Therefore, the volume of the cube is <strong>68, 921</strong> cubic inches.<br>Choice A is incorrect. This is the perimeter, in inches, of the cube.<br>Choice B is incorrect. This is the area, in square inches, of a face of the cube.<br>Choice C is incorrect. This is the surface area, in square inches, of the cube.",
hasFigure: false,
},
{
id: "ec5d4823",
type: "spr",
questionHtml:
"What is the volume, in cubic centimeters, of a right rectangular prism that has a length of 4 centimeters, a width of 9 centimeters, and a height of 10 centimeters?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 360. The volume of a right rectangular prism is calculated by multiplying its dimensions: length, width, and height. Multiplying the values given for these dimensions yields a volume of <strong>4 · 9 · 10 = 360</strong> cubic centimeters.",
hasFigure: false,
},
{
id: "f67e4efc",
type: "mcq",
questionHtml:
"A right circular cylinder has a volume of <strong>45 π</strong>. If the height of the cylinder is 5, what is the radius of the cylinder?",
choices: [
{ label: "A", text: "3" },
{ label: "B", text: "4.5" },
{ label: "C", text: "9" },
{ label: "D", text: "40" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The volume of a right circular cylinder with a radius of r is the product of the area of the base, <strong>π, r²</strong>, and the height, h. The volume of the right circular cylinder described is <strong>45 π</strong> and its height is 5. If the radius is r, it follows that <strong>45 π = π · r, ² · 5</strong>. Dividing both sides of this equation by <strong>5 π</strong> yields <strong>9 = r²</strong>. Taking the square root of both sides yields <strong>r = 3</strong> or <strong>r = 3</strong>. Since r represents the radius, the value must be positive. Therefore, the radius is 3.Choice B is incorrect and may result from finding that the square of the radius is 9, but then from dividing 9 by 2, rather than taking the square root of 9. Choice C is incorrect. This represents the square of the radius. Choice D is incorrect and may result from solving the equation <strong>45 π = π · r, ² · 5</strong> for <strong>r²</strong>, not r, by dividing by <strong>π</strong> on both sides and then by subtracting, not dividing, 5 from both sides.",
hasFigure: false,
},
];
export const AREA_VOL_HARD: PracticeQuestion[] = [
{
id: "306264ab",
type: "mcq",
questionHtml:
"A right triangle has sides of length <strong>2 √(2)</strong>, <strong>6 √(2)</strong>, and <strong>√(80)</strong> units. What is the area of the triangle, in square units?",
choices: [
{ label: "A", text: "<strong>8 √(2) + √(80)</strong>" },
{ label: "B", text: "<strong>12</strong>" },
{ label: "C", text: "<strong>24 √(80)</strong>" },
{ label: "D", text: "<strong>24</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The area, <strong>A</strong>, of a triangle can be found using the formula <strong>A = one half b h</strong>, where <strong>b</strong> is the length of the base of the triangle and <strong>h</strong> is the height of the triangle. It's given that the triangle is a right triangle. Therefore, its base and height can be represented by the two legs. Its also given that the triangle has sides of length <strong>2 √(2)</strong>, <strong>6 √(2)</strong>, and <strong>√(80)</strong> units. Since <strong>√(80)</strong> units is the greatest of these lengths, it's the length of the hypotenuse. Therefore, the two legs have lengths <strong>2 √(2)</strong> and <strong>6 √(2)</strong> units. Substituting these values for <strong>b</strong> and <strong>h</strong> in the formula <strong>A = one half b h</strong> gives <strong>A = one half (2 √(2)) (6 √(2))</strong>, which is equivalent to <strong>A = 6 √(4)</strong> square units, or <strong>A = 12</strong> square units.<br>Choice A is incorrect. This expression represents the perimeter, rather than the area, of the triangle.<br>Choice C is incorrect and may result from conceptual or calculation errors. <br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "310c87fe",
type: "mcq",
questionHtml:
"A cube has a surface area of 54 square meters. What is the volume, in cubic meters, of the cube?",
choices: [
{ label: "A", text: "18" },
{ label: "B", text: "27" },
{ label: "C", text: "36" },
{ label: "D", text: "81" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The surface area of a cube with side length s is equal to <strong>6 s²</strong>. Since the surface area is given as 54 square meters, the equation <strong>54 = 6 s²</strong> can be used to solve for s. Dividing both sides of the equation by 6 yields <strong>9 = s²</strong>. Taking the square root of both sides of this equation yields <strong>3 = s</strong> and <strong>3 = s</strong>. Since the side length of a cube must be a positive value, <strong>s = 3</strong> can be discarded as a possible solution, leaving <strong>s = 3</strong>. The volume of a cube with side length s is equal to <strong>s³</strong>. Therefore, the volume of this cube, in cubic meters, is <strong>3³</strong>, or 27.Choices A, C, and D are incorrect and may result from calculation errors.",
hasFigure: false,
},
{
id: "459dd6c5",
type: "spr",
questionHtml:
"Triangles <strong>italic A italic B italic C</strong> and <strong>italic D italic E italic F</strong> are similar. Each side length of triangle <strong>italic A italic B italic C</strong> is <strong>4</strong> times the corresponding side length of triangle <strong>italic D italic E italic F</strong>. The area of triangle <strong>italic A italic B italic C</strong> is <strong>270</strong> square inches. What is the area, in square inches, of triangle <strong>italic D italic E italic F</strong>?",
choices: [],
correctAnswer: "135/8, 16.87, 16.88",
explanation:
"The correct answer is <strong>(135) / (8)</strong>. It's given that triangles <strong>italic A italic B italic C</strong> and <strong>italic D italic E italic F</strong> are similar and each side length of triangle <strong>italic A italic B italic C</strong> is <strong>4</strong> times the corresponding side length of triangle <strong>italic D italic E italic F</strong>. For two similar triangles, if each side length of the first triangle is <strong>k</strong> times the corresponding side length of the second triangle, then the area of the first triangle is <strong>k²</strong> times the area of the second triangle. Therefore, the area of triangle <strong>italic A italic B italic C</strong> is <strong>4²</strong>, or <strong>16</strong>, times the area of triangle <strong>italic D italic E italic F</strong>. It's given that the area of triangle <strong>italic A italic B italic C</strong> is <strong>270</strong> square inches. Let <strong>a</strong> represent the area, in square inches, of triangle <strong>italic D italic E italic F</strong>. It follows that <strong>270</strong> is <strong>16</strong> times <strong>a</strong>, or <strong>270 = 16 a</strong>. Dividing both sides of this equation by <strong>16</strong> yields <strong>(270) / (16) = a</strong>, which is equivalent to <strong>(135) / (8) = a</strong>. Thus, the area, in square inches, of triangle <strong>italic D italic E italic F</strong> is <strong>(135) / (8)</strong>. Note that 135/8, 16.87, and 16.88 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "5b2b8866",
type: "spr",
questionHtml:
"A rectangular poster has an area of <strong>360</strong> square inches. A copy of the poster is made in which the length and width of the original poster are each increased by <strong>20 % sign</strong>. What is the area of the copy, in square inches?",
choices: [],
correctAnswer: "2592/5, 518.4",
explanation:
"The correct answer is <strong>518.4</strong>. It's given that the area of the original poster is <strong>360</strong> square inches. Let <strong>script l</strong> represent the length, in inches, of the original poster, and let <strong>w</strong> represent the width, in inches, of the original poster. Since the area of a rectangle is equal to its length times its width, it follows that <strong>360 = script l w</strong>. It's also given that a copy of the poster is made in which the length and width of the original poster are each increased by <strong>20 % sign</strong>. It follows that the length of the copy is the length of the original poster plus <strong>20 % sign</strong> of the length of the original poster, which is equivalent to <strong>script l + (20) / (100) script l</strong> inches. This length can be rewritten as <strong>script l + 0.2 script l</strong> inches, or <strong>1.2 script l</strong> inches. Similarly, the width of the copy is the width of the original poster plus <strong>20 % sign</strong> of the width of the original poster, which is equivalent to <strong>w + (20) / (100) w</strong> inches. This width can be rewritten as <strong>w + 0.2 w</strong> inches, or <strong>1.2 w</strong> inches. Since the area of a rectangle is equal to its length times its width, it follows that the area, in square inches, of the copy is equal to <strong>(1.2 script l) (1.2 w)</strong>, which can be rewritten as <strong>(1.2) (1.2) (script l w)</strong>. Since <strong>360 = script l w</strong>, the area, in square inches, of the copy can be found by substituting <strong>360</strong> for <strong>script l w</strong> in the expression <strong>(1.2) (1.2) (script l w)</strong>, which yields <strong>(1.2) (1.2) (360)</strong>, or <strong>518.4</strong>. Therefore, the area of the copy, in square inches, is <strong>518.4</strong>.",
hasFigure: false,
},
{
id: "899c6042",
type: "spr",
questionHtml:
"A right circular cone has a height of <strong>22 centimeters (cm)</strong> and a base with a diameter of <strong>6 cm</strong>. The volume of this cone is <strong>n π cm³</strong>. What is the value of <strong>n</strong>?",
choices: [],
correctAnswer: "66",
explanation:
"The correct answer is <strong>66</strong>. Its given that the right circular cone has a height of <strong>22</strong> centimeters <strong>(cm)</strong> and a base with a diameter of <strong>6 cm</strong>. Since the diameter of the base of the cone is <strong>6 cm</strong>, the radius of the base is <strong>3 cm</strong>. The volume <strong>V</strong>, <strong>in cm³</strong>, of a right circular cone can be found using the formula <strong>V = one third π r² h</strong>, where <strong>h</strong> is the height, <strong>in cm</strong>, and <strong>r</strong> is the radius, <strong>in cm</strong>, of the base of the cone. Substituting <strong>22</strong> for <strong>h</strong> and <strong>3</strong> for <strong>r</strong> in this formula yields <strong>V = one third π (3)² (22)</strong>, or <strong>V = 66 π</strong>. Therefore, the volume of the cone is <strong>66 π italic cm³</strong>. Its given that the volume of the cone is <strong>n π italic cm³</strong>. Therefore, the value of <strong>n</strong> is <strong>66</strong>.",
hasFigure: false,
},
{
id: "93de3f84",
type: "mcq",
questionHtml:
"The volume of right circular cylinder A is 22 cubic centimeters. What is the volume, in cubic centimeters, of a right circular cylinder with twice the radius and half the height of cylinder A?",
choices: [
{ label: "A", text: "11" },
{ label: "B", text: "22" },
{ label: "C", text: "44" },
{ label: "D", text: "66" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The volume of right circular cylinder A is given by the expression <strong>π r² · h</strong>, where r is the radius of its circular base and h is its height. The volume of a cylinder with twice the radius and half the height of cylinder A is given by <strong>π · (2 r, ), ² · one half h</strong>, which is equivalent to <strong>4 π r² · one half h, and = 2 π r² · h</strong>. Therefore, the volume is twice the volume of cylinder A, or <strong>2 · 22 = 44</strong>.Choice A is incorrect and likely results from not multiplying the radius of cylinder A by 2. Choice B is incorrect and likely results from not squaring the 2 in 2r when applying the volume formula. Choice D is incorrect and likely results from a conceptual error.",
hasFigure: false,
},
{
id: "9966235e",
type: "mcq",
questionHtml:
"A cube has an edge length of <strong>68</strong> inches. A solid sphere with a radius of <strong>34</strong> inches is inside the cube, such that the sphere touches the center of each face of the cube. To the nearest cubic inch, what is the volume of the space in the cube not taken up by the sphere?",
choices: [
{ label: "A", text: "<strong>149, 796</strong>" },
{ label: "B", text: "<strong>164, 500</strong>" },
{ label: "C", text: "<strong>190, 955</strong>" },
{ label: "D", text: "<strong>310, 800</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The volume of a cube can be found by using the formula <strong>V = s³</strong>, where <strong>V</strong> is the volume and <strong>s</strong> is the edge length of the cube. Therefore, the volume of the given cube is <strong>V = 68³</strong>, or <strong>314, 432</strong> cubic inches. The volume of a sphere can be found by using the formula <strong>V = four thirds π r³</strong> , where <strong>V</strong> is the volume and <strong>r</strong> is the radius of the sphere. Therefore, the volume of the given sphere is <strong>V = four thirds π (34)³</strong>, or approximately <strong>164, 636</strong> cubic inches. The volume of the space in the cube not taken up by the sphere is the difference between the volume of the cube and volume of the sphere. Subtracting the approximate volume of the sphere from the volume of the cube gives <strong>314, 432 164, 636 = 149, 796</strong> cubic inches.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "9f934297",
type: "spr",
questionHtml:
"A right rectangular prism has a length of <strong>28 centimeters (cm)</strong>, a width of <strong>15 cm</strong>, and a height of <strong>16 cm</strong>. What is the surface area, <strong>in cm²</strong>, of the right rectangular prism?",
choices: [],
correctAnswer: "2216",
explanation:
"The correct answer is <strong>2, 216</strong>. The surface area of a prism is the sum of the areas of all its faces. A right rectangular prism consists of six rectangular faces, where opposite faces are congruent. It's given that this prism has a length of <strong>28 cm</strong>, a width of <strong>15 cm</strong>, and a height of <strong>16 cm</strong>. Thus, for this prism, there are two faces with area <strong>(28) (15) cm²</strong>, two faces with area <strong>(28) (16) cm²</strong>, and two faces with area <strong>(15) (16) cm²</strong>. Therefore, the surface area, <strong>in cm²</strong>, of the right rectangular prism is <strong>2 (28) (15) + 2 (28) (16) + 2 (15) (16)</strong>, or <strong>2, 216</strong>.",
hasFigure: false,
},
{
id: "a07ed090",
type: "mcq",
questionHtml:
"The figure shown is a right circular cylinder with a radius of <strong>r</strong> and height of <strong>h</strong>. A second right circular cylinder (not shown) has a volume that is <strong>392</strong> times as large as the volume of the cylinder shown. Which of the following could represent the radius <strong>R</strong>, in terms of <strong>r</strong>, and the height <strong>H</strong>, in terms of <strong>h</strong>, of the second cylinder?",
choices: [
{
label: "A",
text: "<strong>R = 8 r</strong> and <strong>H = 7 h</strong>",
},
{
label: "B",
text: "<strong>R = 8 r</strong> and <strong>H = 49 h</strong>",
},
{
label: "C",
text: "<strong>R = 7 r</strong> and <strong>H = 8 h</strong>",
},
{
label: "D",
text: "<strong>R = 49 r</strong> and <strong>H = 8 h</strong>",
},
],
correctAnswer: "C",
explanation:
"Choice C is correct. The volume of a right circular cylinder is equal to <strong>π a² b</strong>, where <strong>a</strong> is the radius of a base of the cylinder and <strong>b</strong> is the height of the cylinder. Its given that the cylinder shown has a radius of <strong>r</strong> and a height of <strong>h</strong>. It follows that the volume of the cylinder shown is equal to <strong>π r² h</strong>. Its given that the second right circular cylinder has a radius of <strong>R</strong> and a height of <strong>H</strong>. It follows that the volume of the second cylinder is equal to <strong>π R² H</strong>. Choice C gives <strong>R = 7 r</strong> and <strong>H = 8 h</strong>. Substituting <strong>7 r</strong> for <strong>R</strong> and <strong>8 h</strong> for <strong>H</strong> in the expression that represents the volume of the second cylinder yields <strong>π (7 r)² (8 h)</strong>, or <strong>π (49 r²) (8 h)</strong>, which is equivalent to <strong>π (392 r² h)</strong>, or <strong>392 (π r² h)</strong>. This expression is equal to <strong>392</strong> times the volume of the cylinder shown, <strong>π r² h</strong>. Therefore, <strong>R = 7 r</strong> and <strong>H = 8 h</strong> could represent the radius <strong>R</strong>, in terms of <strong>r</strong>, and the height <strong>H</strong>, in terms of <strong>h</strong>, of the second cylinder.<br>Choice A is incorrect. Substituting <strong>8 r</strong> for <strong>R</strong> and <strong>7 h</strong> for <strong>H</strong> in the expression that represents the volume of the second cylinder yields <strong>π (8 r)² (7 h)</strong>, or <strong>π (64 r²) (7 h)</strong>, which is equivalent to <strong>π (448 r² h)</strong>, or <strong>448 (π r² h)</strong>. This expression is equal to <strong>448</strong>, not <strong>392</strong>, times the volume of the cylinder shown. <br>Choice B is incorrect. Substituting <strong>8 r</strong> for <strong>R</strong> and <strong>49 h</strong> for <strong>H</strong> in the expression that represents the volume of the second cylinder yields <strong>π (8 r)² (49 h)</strong>, or <strong>π (64 r²) (49 h)</strong>, which is equivalent to <strong>π (3, 136 r² h)</strong>, or <strong>3, 136 (π r² h)</strong>. This expression is equal to <strong>3, 136</strong>, not <strong>392</strong>, times the volume of the cylinder shown.<br>Choice D is incorrect. Substituting <strong>49 r</strong> for <strong>R</strong> and <strong>8 h</strong> for <strong>H</strong> in the expression that represents the volume of the second cylinder yields <strong>π (49 r)² (8 h)</strong>, or <strong>π (2, 401 r²) (8 h)</strong>, which is equivalent to <strong>π (19, 208 r² h)</strong>, or <strong>19, 208 (π r² h)</strong>. This expression is equal to <strong>19, 208</strong>, not <strong>392</strong>, times the volume of the cylinder shown.",
hasFigure: true,
figureUrl: "/practice-images/a07ed090_svg1.svg",
},
{
id: "b0dc920d",
type: "mcq",
questionHtml:
"A manufacturer determined that right cylindrical containers with a height that is 4 inches longer than the radius offer the optimal number of containers to be displayed on a shelf. Which of the following expresses the volume, V, in cubic inches, of such containers, where r is the radius, in inches?",
choices: [
{ label: "A", text: "<strong>V = 4 π r³</strong>" },
{ label: "B", text: "<strong>V = π · (2 r, ), ³</strong>" },
{ label: "C", text: "<strong>V = π r² + 4 π r</strong>" },
{ label: "D", text: "<strong>V = π r³ + 4 π r²</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The volume, V, of a right cylinder is given by the formula <strong>V = π r² · h</strong>, where r represents the radius of the base of the cylinder and h represents the height. Since the height is 4 inches longer than the radius, the expression <strong>r + 4</strong> represents the height of each cylindrical container. It follows that the volume of each container is represented by the equation <strong>V = π r² · (r + 4, )</strong>. Distributing the expression <strong>π r²</strong> into each term in the parentheses yields <strong>V = π r³ + 4 π r²</strong>.Choice A is incorrect and may result from representing the height as <strong>4 r</strong> instead of <strong>r + 4</strong>. Choice B is incorrect and may result from representing the height as <strong>2 r</strong> instead of <strong>r + 4</strong>. Choice C is incorrect and may result from representing the volume of a right cylinder as <strong>V = π r h</strong> instead of <strong>V = π r² · h</strong>.",
hasFigure: false,
},
{
id: "ba8ca563",
type: "spr",
questionHtml:
"A cube has a volume of <strong>474, 552</strong> cubic units. What is the surface area, in square units, of the cube?",
choices: [],
correctAnswer: "36504",
explanation:
"The correct answer is <strong>36, 504</strong>. The volume of a cube can be found using the formula <strong>V = s³</strong>, where <strong>s</strong> represents the edge length of a cube. Its given that this cube has a volume of <strong>474, 552</strong> cubic units. Substituting <strong>474, 552</strong> for <strong>V</strong> in <strong>V = s³</strong> yields <strong>474, 552 = s³</strong>. Taking the cube root of both sides of this equation yields <strong>78 = s</strong>. Thus, the edge length of the cube is <strong>78</strong> units. Since each face of a cube is a square, it follows that each face has an edge length of <strong>78</strong> units. The area of a square can be found using the formula <strong>A = s²</strong>. Substituting <strong>78</strong> for <strong>s</strong> in this formula yields <strong>A = 78²</strong>, or <strong>A = 6, 084</strong>. Therefore, the area of one face of this cube is <strong>6, 084</strong> square units. Since a cube has <strong>6</strong> faces, the surface area, in square units, of this cube is <strong>6 (6, 084)</strong>, or <strong>36, 504</strong>.",
hasFigure: false,
},
{
id: "dc71597b",
type: "mcq",
questionHtml:
"A right circular cone has a volume of <strong>one third, π</strong> cubic feet and a height of 9 feet. What is the radius, in feet, of the base of the cone?",
choices: [
{ label: "A", text: "<strong>one third</strong>" },
{
label: "B",
text: "<strong>the fraction 1 over the √ 3, end fraction</strong>",
},
{ label: "C", text: "<strong>the √ 3</strong>" },
{ label: "D", text: "<strong>3</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The equation for the volume of a right circular cone is <strong>V = one third π r² · h</strong>. Its given that the volume of the right circular cone is <strong>one third π</strong> cubic feet and the height is 9 feet. Substituting these values for V and h, respectively, gives <strong>one third π = one third π r² · 9</strong>. Dividing both sides of the equation by <strong>one third π</strong> gives <strong>1 = r² · 9</strong>. Dividing both sides of the equation by 9 gives <strong>one ninth = r²</strong>. Taking the square root of both sides results in two possible values for the radius, <strong>the √ one ninth</strong> or <strong>the of the √ one ninth</strong>. Since the radius cant have a negative value, that leaves <strong>the √ one ninth</strong> as the only possibility. Applying the quotient property of square roots, <strong>the √ the fraction a, over b = the fraction the √ a, over the √ b</strong>, results in <strong>r = the fraction the √ 1 over the √ 9</strong>, or <strong>r = one third</strong>.Choices B and C are incorrect and may result from incorrectly evaluating <strong>the √ one ninth</strong>. Choice D is incorrect and may result from solving <strong>r² = 9</strong> instead of <strong>r² = one ninth</strong>.",
hasFigure: false,
},
{
id: "e5c57163",
type: "spr",
questionHtml:
"Square A has side lengths that are <strong>166</strong> times the side lengths of square B. The area of square A is <strong>k</strong> times the area of square B. What is the value of <strong>k</strong>?",
choices: [],
correctAnswer: "27556",
explanation:
"The correct answer is <strong>27, 556</strong>. The area of a square is <strong>s²</strong>, where <strong>s</strong> is the side length of the square. Let <strong>x</strong> represent the length of each side of square B. Substituting <strong>x</strong> for <strong>s</strong> in <strong>s²</strong> yields <strong>x²</strong>. It follows that the area of square B is <strong>x²</strong>. Its given that square A has side lengths that are <strong>166</strong> times the side lengths of square B. Since <strong>x</strong> represents the length of each side of square B, the length of each side of square A can be represented by the expression <strong>166 x</strong>. It follows that the area of square A is <strong>(166 x)²</strong>, or <strong>27, 556 x²</strong>. Its given that the area of square A is <strong>k</strong> times the area of square B. Since the area of square A is equal to <strong>27, 556 x²</strong>, and the area of square B is equal to <strong>x²</strong>, an equation representing the given statement is <strong>27, 556 x² = k x²</strong>. Since <strong>x</strong> represents the length of each side of square B, the value of <strong>x</strong> must be positive. Therefore, the value of <strong>x²</strong> is also positive, so it does not equal <strong>0</strong>. Dividing by <strong>x²</strong> on both sides of the equation <strong>27, 556 x² = k x²</strong> yields <strong>27, 556 = k</strong>. Therefore, the value of <strong>k</strong> is <strong>27, 556</strong>.",
hasFigure: false,
},
{
id: "eb70d2d0",
type: "spr",
questionHtml:
"Moving from left to right, the points have the following coordinates:<br><br>(negative 3 comma 4)<br>(4 comma negative 3)<br>(5 comma 3)<br><br>What is the area, in square units, of the triangle formed by connecting the three points shown?",
choices: [],
correctAnswer: "24.5, 49/2",
explanation:
"The correct answer is <strong>24.5</strong>. It's given that a triangle is formed by connecting the three points shown, which are <strong>(3, 4)</strong>, <strong>(5, 3)</strong>, and <strong>(4 3)</strong>. Let this triangle be triangle A. The area of triangle A can be found by calculating the area of the rectangle that circumscribes it and subtracting the areas of the three triangles that are inside the rectangle but outside triangle A. The rectangle formed by the points <strong>(3, 4)</strong>, <strong>(5, 4)</strong>, <strong>(5 3)</strong>, and <strong>(3 3)</strong> circumscribes triangle A. The width, in units, of this rectangle can be found by calculating the distance between the points <strong>(5, 4)</strong> and <strong>(5 3)</strong>. This distance is <strong>4 (3)</strong>, or <strong>7</strong>. The length, in units, of this rectangle can be found by calculating the distance between the points <strong>(5, 4)</strong> and <strong>(3, 4)</strong>. This distance is <strong>5 (3)</strong>, or <strong>8</strong>. It follows that the area, in square units, of the rectangle is <strong>(7) (8)</strong>, or <strong>56</strong>. One of the triangles that lies inside the rectangle but outside triangle A is formed by the points <strong>(3, 4)</strong>, <strong>(5, 4)</strong>, and <strong>(5, 3)</strong>. The length, in units, of a base of this triangle can be found by calculating the distance between the points <strong>(5, 4)</strong> and <strong>(5, 3)</strong>. This distance is <strong>4 3</strong>, or <strong>1</strong>. The corresponding height, in units, of this triangle can be found by calculating the distance between the points <strong>(5, 4)</strong> and <strong>(3, 4)</strong>. This distance is <strong>5 (3)</strong>, or <strong>8</strong>. It follows that the area, in square units, of this triangle is <strong>one half (8) (1)</strong>, or <strong>4</strong>. A second triangle that lies inside the rectangle but outside triangle A is formed by the points <strong>(4 3)</strong>, <strong>(5, 3)</strong>, and <strong>(5 3)</strong>. The length, in units, of a base of this triangle can be found by calculating the distance between the points <strong>(5, 3)</strong> and <strong>(5 3)</strong>. This distance is <strong>3 (3)</strong> , or <strong>6</strong>. The corresponding height, in units, of this triangle can be found by calculating the distance between the points <strong>(5 3)</strong> and <strong>(4 3)</strong>. This distance is <strong>5 4</strong>, or <strong>1</strong>. It follows that the area, in square units, of this triangle is <strong>one half (1) (6)</strong>, or <strong>3</strong>. The third triangle that lies inside the rectangle but outside triangle A is formed by the points <strong>(3, 4)</strong>, <strong>(3 3)</strong>, and <strong>(4 3)</strong>. The length, in units, of a base of this triangle can be found by calculating the distance between the points <strong>(4 3)</strong> and <strong>(3 3)</strong>. This distance is <strong>4 (3)</strong>, or <strong>7</strong>. The corresponding height, in units, of this triangle can be found by calculating the distance between the points <strong>(3, 4)</strong> and <strong>(3 3)</strong>. This distance is <strong>4 (3)</strong>, or <strong>7</strong>. It follows that the area, in square units, of this triangle is <strong>one half (7) (7)</strong>, or <strong>24.5</strong>. Thus, the area, in square units, of the triangle formed by connecting the three points shown is <strong>56 4 3 24.5</strong>, or <strong>24.5</strong>. Note that 24.5 and 49/2 are examples of ways to enter a correct answer.",
hasFigure: true,
figureUrl: "/practice-images/eb70d2d0_svg1.svg",
},
{
id: "f243c383",
type: "mcq",
questionHtml:
"Two identical rectangular prisms each have a height of <strong>90 centimeters (cm)</strong>. The base of each prism is a square, and the surface area of each prism is <strong>K cm²</strong>. If the prisms are glued together along a square base, the resulting prism has a surface area of <strong>(92) / (47) K cm²</strong>. What is the side length, in <strong>cm</strong>, of each square base?",
choices: [
{ label: "A", text: "<strong>4</strong>" },
{ label: "B", text: "<strong>8</strong>" },
{ label: "C", text: "<strong>9</strong>" },
{ label: "D", text: "<strong>16</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Let <strong>x</strong> represent the side length, in <strong>cm</strong>, of each square base. If the two prisms are glued together along a square base, the resulting prism has a surface area equal to twice the surface area of one of the prisms, minus the area of the two square bases that are being glued together, which yields <strong>2 K 2 x² cm²</strong> . Its given that this resulting surface area is equal to <strong>(92) / (47) K cm²</strong>, so <strong>2 K 2 x² = (92) / (47) K</strong>. Subtracting <strong>(92) / (47) K</strong> from both sides of this equation yields <strong>2 K (92) / (47) K 2 x² = 0</strong>. This equation can be rewritten by multiplying <strong>2 K</strong> on the left-hand side by <strong>(47) / (47)</strong>, which yields <strong>(94) / (47) K (92) / (47) K 2 x² = 0</strong>, or <strong>two forty sevenths K 2 x² = 0</strong>. Adding <strong>2 x²</strong> to both sides of this equation yields <strong>two forty sevenths K = 2 x²</strong>. Multiplying both sides of this equation by <strong>(47) / (2)</strong> yields <strong>K = 47 x²</strong>. The surface area <strong>K</strong>, in <strong>cm²</strong>, of each rectangular prism is equivalent to the sum of the areas of the two square bases and the areas of the four lateral faces. Since the height of each rectangular prism is <strong>90 cm</strong> and the side length of each square base is <strong>x cm</strong>, it follows that the area of each square base is <strong>x² cm²</strong> and the area of each lateral face is <strong>90 x cm²</strong>. Therefore, the surface area of each rectangular prism can be represented by the expression <strong>2 x² + 4 (90 x)</strong>, or <strong>2 x² + 360 x</strong>. Substituting this expression for <strong>K</strong> in the equation <strong>K = 47 x²</strong> yields <strong>2 x² + 360 x = 47 x²</strong>. Subtracting <strong>2 x²</strong> and <strong>360 x</strong> from both sides of this equation yields <strong>0 = 45 x² 360 x</strong>. Factoring <strong>x</strong> from the right-hand side of this equation yields <strong>0 = x (45 x 360)</strong>. Applying the zero product property, it follows that <strong>x = 0</strong> and <strong>45 x 360 = 0</strong>. Adding <strong>360</strong> to both sides of the equation <strong>45 x 360 = 0</strong> yields <strong>45 x = 360</strong>. Dividing both sides of this equation by <strong>45</strong> yields <strong>x = 8</strong>. Since a side length of a rectangular prism cant be <strong>0</strong>, the length of each square base is <strong>8</strong> <strong>cm</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "f329442c",
type: "mcq",
questionHtml:
"Circle <strong>A</strong> has a radius of <strong>3 n</strong> and circle <strong>B</strong> has a radius of <strong>129 n</strong>, where <strong>n</strong> is a positive constant. The area of circle <strong>B</strong> is how many times the area of circle <strong>A</strong>?",
choices: [
{ label: "A", text: "<strong>43</strong>" },
{ label: "B", text: "<strong>86</strong>" },
{ label: "C", text: "<strong>129</strong>" },
{ label: "D", text: "<strong>1, 849</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The area of a circle can be found by using the formula <strong>A = π r²</strong>, where <strong>A</strong> is the area and <strong>r</strong> is the radius of the circle. Its given that the radius of circle A is <strong>3 n</strong>. Substituting this value for <strong>r</strong> into the formula <strong>A = π r²</strong> gives <strong>A = π (3 n)²</strong>, or <strong>9 π n²</strong>. Its also given that the radius of circle B is <strong>129 n</strong>. Substituting this value for <strong>r</strong> into the formula <strong>A = π r²</strong> gives <strong>A = π (129 n)²</strong>, or <strong>16, 641 π n²</strong>. Dividing the area of circle B by the area of circle A gives <strong>(16, 641 π n²) / (9 π n²)</strong>, which simplifies to <strong>1, 849</strong>. Therefore, the area of circle B is <strong>1, 849</strong> times the area of circle A.<br>Choice A is incorrect. This is how many times greater the radius of circle B is than the radius of circle A.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect. This is the coefficient on the term that describes the radius of circle B.",
hasFigure: false,
},
{
id: "f7e626b2",
type: "mcq",
questionHtml:
"The dimensions of a right rectangular prism are 4 inches by 5 inches by 6 inches. What is the surface area, in square inches, of the prism?",
choices: [
{ label: "A", text: "30" },
{ label: "B", text: "74" },
{ label: "C", text: "120" },
{ label: "D", text: "148" },
],
correctAnswer: "",
explanation:
"Choice D is correct. The surface area is found by summing the area of each face. A right rectangular prism consists of three pairs of congruent rectangles, so the surface area is found by multiplying the areas of three adjacent rectangles by 2 and adding these products. For this prism, the surface area is equal to <strong>2 · (4 · 5, ) + 2 · (5 · 6, ) + 2 · (4 · 6, )</strong>, or <strong>2 · 20 + 2 · 30 + 2 · 24</strong>, which is equal to 148.Choice A is incorrect. This is the area of one of the faces of the prism. Choice B is incorrect and may result from adding the areas of three adjacent rectangles without multiplying by 2. Choice C is incorrect. This is the volume, in cubic inches, of the prism.",
hasFigure: false,
},
];

424
src/data/math/circles.ts Normal file
View File

@ -0,0 +1,424 @@
import { type PracticeQuestion } from "../../types/lesson";
export const CIRCLES_EASY: PracticeQuestion[] = [
{
id: "23c5fcce",
type: "mcq",
questionHtml:
"The circle above with center O has a circumference of 36. What is the length of minor arc <strong>A, C</strong>?",
choices: [
{ label: "A", text: "9" },
{ label: "B", text: "12" },
{ label: "C", text: "18" },
{ label: "D", text: "36" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. A circle has 360 degrees of arc. In the circle shown, O is the center of the circle and <strong>angle A, O C</strong> is a central angle of the circle. From the figure, the two diameters that meet to form <strong>angle A, O C</strong> are perpendicular, so the measure of <strong>angle A, O C</strong> is <strong>90 °</strong>. Therefore, the length of minor arc <strong>A, C</strong> is <strong>the fraction 90 over 360</strong> of the circumference of the circle. Since the circumference of the circle is 36, the length of minor arc <strong>A, C</strong> is <strong>the fraction 90 over 360, end fraction · 36 = 9</strong>.Choices B, C, and D are incorrect. The perpendicular diameters divide the circumference of the circle into four equal arcs; therefore, minor arc <strong>A, C</strong> is <strong>one fourth</strong> of the circumference. However, the lengths in choices B and C are, respectively, <strong>one third</strong> and <strong>one half</strong> the circumference of the circle, and the length in choice D is the length of the entire circumference. None of these lengths is <strong>one fourth</strong> the circumference.",
hasFigure: true,
figureUrl: "/practice-images/23c5fcce_img1.png",
},
];
export const CIRCLES_MEDIUM: PracticeQuestion[] = [
{
id: "0815a5af",
type: "mcq",
questionHtml:
"The center of the circle is point upper O.<br>Points upper S, upper R, upper Q, and upper P are on the circle.<br>Line segment upper P upper R is a diameter of the circle.<br>Line segment upper Q upper S is a diameter of the circle.<br>Diameters upper P upper R and upper Q upper S intersect at point upper O.<br>A note indicates the figure is not drawn to scale.<br><br>The circle shown has center <strong>O</strong>, circumference <strong>144 π</strong>, and diameters <strong>P R</strong> and <strong>Q S</strong>. The length of arc <strong>P S</strong> is twice the length of arc <strong>P Q</strong>. What is the length of arc <strong>Q R</strong>?",
choices: [
{ label: "A", text: "<strong>24 π</strong>" },
{ label: "B", text: "<strong>48 π</strong>" },
{ label: "C", text: "<strong>72 π</strong>" },
{ label: "D", text: "<strong>96 π</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Since <strong>P R</strong> and <strong>Q S</strong> are diameters of the circle shown, <strong>O S</strong>, <strong>O R</strong>, <strong>O P</strong>, and <strong>O Q</strong> are radii of the circle and are therefore congruent. Since <strong>angle S O P</strong> and <strong>angle R O Q</strong> are vertical angles, they are congruent. Therefore, arc <strong>P S</strong> and arc <strong>Q R</strong> are formed by congruent radii and have the same angle measure, so they are congruent arcs. Similarly, <strong>angle S O R</strong> and <strong>angle P O Q</strong> are vertical angles, so they are congruent. Therefore, arc <strong>S R</strong> and arc <strong>P Q</strong> are formed by congruent radii and have the same angle measure, so they are congruent arcs. Let <strong>x</strong> represent the length of arc <strong>S R</strong>. Since arc <strong>S R</strong> and arc <strong>P Q</strong> are congruent arcs, the length of arc <strong>P Q</strong> can also be represented by <strong>x</strong>. Its given that the length of arc <strong>P S</strong> is twice the length of arc <strong>P Q</strong>. Therefore, the length of arc <strong>P S</strong> can be represented by the expression <strong>2 x</strong>. Since arc <strong>P S</strong> and arc <strong>Q R</strong> are congruent arcs, the length of arc <strong>Q R</strong> can also be represented by <strong>2 x</strong>. This gives the expression <strong>x + x + 2 x + 2 x</strong>. Since it's given that the circumference is <strong>144 π</strong>, the expression <strong>x + x + 2 x + 2 x</strong> is equal to <strong>144 π</strong>. Thus <strong>x + x + 2 x + 2 x = 144 π</strong>, or <strong>6 x = 144 π</strong>. Dividing both sides of this equation by <strong>6</strong> yields <strong>x = 24 π</strong>. Therefore, the length of arc <strong>Q R</strong> is <strong>2 (24 π)</strong>, or <strong>48 π</strong>.<br>Choice A is incorrect. This is the length of arc <strong>P Q</strong>, not arc <strong>Q R</strong>.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/0815a5af_svg1.svg",
},
{
id: "74d8b897",
type: "spr",
questionHtml:
"An angle has a measure of <strong>(9 π) / (20)</strong> radians. What is the measure of the angle in degrees?",
choices: [],
correctAnswer: "81",
explanation:
"The correct answer is <strong>81</strong>. The measure of an angle, in degrees, can be found by multiplying its measure, in radians, by <strong>(180 °) / (π radians)</strong>. Multiplying the given angle measure, <strong>(9 π) / (20)</strong> radians, by <strong>(180 °) / (π radians)</strong> yields <strong>((9 π) / (20) radians) ((180 °) / (π radians))</strong>, which is equivalent to <strong>81</strong> degrees.",
hasFigure: false,
},
{
id: "82c8325f",
type: "mcq",
questionHtml:
"A circle in the xy-plane has its center at <strong>(4, 5)</strong> and the point <strong>(8, 8)</strong> lies on the circle. Which equation represents this circle?",
choices: [
{ label: "A", text: "<strong>(x 4)² + (y + 5)² = 5</strong>" },
{ label: "B", text: "<strong>(x + 4)² + (y 5)² = 5</strong>" },
{ label: "C", text: "<strong>(x 4)² + (y + 5)² = 25</strong>" },
{ label: "D", text: "<strong>(x + 4)² + (y 5)² = 25</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. A circle in the xy-plane can be represented by an equation of the form <strong>(x h)² + (y k)² = r²</strong>, where <strong>(h, k)</strong> is the center of the circle and <strong>r</strong> is the length of a radius of the circle. It's given that the circle has its center at <strong>(4, 5)</strong>. Therefore, <strong>h = 4</strong> and <strong>k = 5</strong>. Substituting <strong>4</strong> for <strong>h</strong> and <strong>5</strong> for <strong>k</strong> in the equation <strong>(x h)² + (y k)² = r²</strong> yields <strong>(x (4))² + (y 5)² = r²</strong>, or <strong>(x + 4)² + (y 5)² = r²</strong>. It's also given that the point <strong>(8, 8)</strong> lies on the circle. Substituting <strong>8</strong> for <strong>x</strong> and <strong>8</strong> for <strong>y</strong> in the equation <strong>(x + 4)² + (y 5)² = r²</strong> yields <strong>(8 + 4)² + (8 5)² = r²</strong>, or <strong>(4)² + (3)² = r²</strong>, which is equivalent to <strong>16 + 9 = r²</strong>, or <strong>25 = r²</strong>. Substituting <strong>25</strong> for <strong>r²</strong> in the equation <strong>(x + 4)² + (y 5)² = r²</strong> yields <strong>(x + 4)² + (y 5)² = 25</strong>. Thus, the equation <strong>(x + 4)² + (y 5)² = 25</strong> represents the circle.<br>Choice A is incorrect. The circle represented by this equation has its center at <strong>(4 5)</strong>, not <strong>(4, 5)</strong>, and the point <strong>(8, 8)</strong> doesn't lie on the circle.<br>Choice B is incorrect. The point <strong>(8, 8)</strong> doesn't lie on the circle represented by this equation.<br>Choice C is incorrect. The circle represented by this equation has its center at <strong>(4 5)</strong>, not <strong>(4, 5)</strong>, and the point <strong>(8, 8)</strong> doesn't lie on the circle.",
hasFigure: false,
},
{
id: "856372ca",
type: "mcq",
questionHtml:
"In the xy-plane, a circle with radius 5 has center <strong>with coordinates 8, 6</strong>. Which of the following is an equation of the circle?",
choices: [
{ label: "A", text: "<strong>(x 8, ), ² + (y + 6, ), ² = 25</strong>" },
{ label: "B", text: "<strong>(x + 8, ), ² + (y 6, ), ² = 25</strong>" },
{ label: "C", text: "<strong>(x 8, ), ² + (y + 6, ), ² = 5</strong>" },
{ label: "D", text: "<strong>(x + 8, ), ² + (y 6, ), ² = 5</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. An equation of a circle is <strong>(x h, ), ² + (y k, ), ² = r²</strong>, where the center of the circle is <strong>h, k</strong> and the radius is r. Its given that the center of this circle is <strong>8, 6</strong> and the radius is 5. Substituting these values into the equation gives <strong>(x 8, ), ² + (y 6, ), ² = 5²</strong>, or <strong>(x + 8, ), ² + (y 6, ), ² = 25</strong>.Choice A is incorrect. This is an equation of a circle that has center <strong>8 6</strong>. Choice C is incorrect. This is an equation of a circle that has center <strong>8 6</strong> and radius <strong>the √ 5</strong>. Choice D is incorrect. This is an equation of a circle that has radius  <strong>the √ 5</strong>.",
hasFigure: false,
},
{
id: "8e7689e0",
type: "spr",
questionHtml:
"The number of radians in a 720-degree angle can be written as <strong>a · π</strong>, where a is a constant. What is the value of a ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 4. There are <strong>π</strong> radians in a <strong>180 °</strong> angle. An angle measure of <strong>720 °</strong> is 4 times greater than an angle measure of <strong>180 °</strong>. Therefore, the number of radians in a <strong>720 °</strong> angle is <strong>4 π</strong>.",
hasFigure: false,
},
{
id: "95ba2d09",
type: "mcq",
questionHtml:
"In the xy-plane above, points P, Q, R, and T lie on the circle with center O. The degree measures of angles <strong>P O Q</strong> and <strong>R O T</strong> are each 30°. What is the radian measure of angle <strong>Q O R</strong> ?",
choices: [
{ label: "A", text: "<strong>five sixths, π</strong>" },
{ label: "B", text: "<strong>three fourths, π</strong>" },
{ label: "C", text: "<strong>two thirds, π</strong>" },
{ label: "D", text: "<strong>one third, π</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Because points T, O, and P all lie on the x-axis, they form a line. Since the angles on a line add up to <strong>180 °</strong>, and its given that angles POQ and ROT each measure <strong>30 °</strong>, it follows that the measure of angle QOR is <strong>180 ° 30 ° 30 ° = 120 °</strong>. Since the arc of a complete circle is <strong>360 °</strong> or <strong>2 π</strong> radians, a proportion can be set up to convert the measure of angle QOR from degrees to radians: <strong>the fraction 360 ° over 2 π radians = the fraction 120 ° over x radians</strong>, where x is the radian measure of angle QOR. Multiplying each side of the proportion by <strong>2 π x</strong> gives <strong>360 x = 240 π</strong>. Solving for x gives <strong>the fraction 240 over 360 · π</strong>, or <strong>two thirds π</strong>.Choice A is incorrect and may result from subtracting only angle POQ from <strong>180 °</strong>to get a value of <strong>150 °</strong>and then finding the radian measure equivalent to that value. Choice B is incorrect and may result from a calculation error. Choice D is incorrect and may result from calculating the sum of the angle measures, in radians, of angles POQ and ROT.",
hasFigure: true,
figureUrl: "/practice-images/95ba2d09_img1.png",
},
{
id: "a0cacec1",
type: "spr",
questionHtml:
"An angle has a measure of <strong>(16 π) / (15)</strong> radians. What is the measure of the angle, in degrees?",
choices: [],
correctAnswer: "192",
explanation:
"The correct answer is <strong>192</strong>. The measure of an angle, in degrees, can be found by multiplying its measure, in radians, by <strong>(180 °) / (π radians)</strong>. Multiplying the given angle measure, <strong>(16 π) / (15) radians</strong>, by <strong>(180 °) / (π radians)</strong> yields <strong>((16 π) / (15) radians) ((180 °) / (π r a d i a n s))</strong>, which simplifies to <strong>192</strong> degrees.",
hasFigure: false,
},
{
id: "f1c1e971",
type: "mcq",
questionHtml:
"The measure of angle <strong>R</strong> is <strong>(2 π) / (3)</strong> radians. The measure of angle <strong>T</strong> is <strong>(5 π) / (12)</strong> radians greater than the measure of angle <strong>R</strong>. What is the measure of angle <strong>T</strong>, in degrees?",
choices: [
{ label: "A", text: "<strong>75</strong>" },
{ label: "B", text: "<strong>120</strong>" },
{ label: "C", text: "<strong>195</strong>" },
{ label: "D", text: "<strong>390</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that the measure of angle <strong>R</strong> is <strong>(2 π) / (3)</strong> radians, and the measure of angle <strong>T</strong> is <strong>(5 π) / (12)</strong> radians greater than the measure of angle <strong>R</strong>. Therefore, the measure of angle <strong>T</strong> is equal to <strong>(2 π) / (3) + (5 π) / (12)</strong> radians. Multiplying <strong>(2 π) / (3)</strong> by <strong>four fourths</strong> to get a common denominator with <strong>(5 π) / (12)</strong> yields <strong>(8 π) / (12)</strong>. Therefore, <strong>(2 π) / (3) + (5 π) / (12)</strong> is equivalent to <strong>(8 π) / (12) + (5 π) / (12)</strong>, or <strong>(13 π) / (12)</strong>. Therefore, the measure of angle <strong>T</strong> is <strong>(13 π) / (12)</strong> radians. The measure of angle <strong>T</strong>, in degrees, can be found by multiplying its measure, in radians, by <strong>(180) / (π)</strong>. This yields <strong>(13 π) / (12) · (180) / (π)</strong>, which is equivalent to <strong>195</strong> degrees. Therefore, the measure of angle <strong>T</strong> is <strong>195</strong> degrees.<br>Choice A is incorrect. This is the number of degrees that the measure of angle <strong>T</strong> is greater than the measure of angle <strong>R</strong>.<br>Choice B is incorrect. This is the measure of angle <strong>R</strong>, in degrees.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
];
export const CIRCLES_HARD: PracticeQuestion[] = [
{
id: "2266984b",
type: "mcq",
questionHtml:
"The equation above defines a circle in the xy-plane. What are the coordinates of the center of the circle?",
choices: [
{ label: "A", text: "<strong>20 16</strong>" },
{ label: "B", text: "<strong>10 8</strong>" },
{ label: "C", text: "<strong>10, 8</strong>" },
{ label: "D", text: "<strong>20, 16</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The standard equation of a circle in the xy-plane is of the form <strong>(x h, ), ² + (y k, ), ² = r²</strong>, where <strong>the ordered pair h, k</strong> are the coordinates of the center of the circle and r is the radius. The given equation can be rewritten in standard form by completing the squares. So the sum of the first two terms, <strong>x² + 20 x</strong>, needs a 100 to complete the square, and the sum of the second two terms, <strong>y² + 16 y</strong>, needs a 64 to complete the square. Adding 100 and 64 to both sides of the given equation yields <strong>(x² + 20 x + 100, ) + (y² + 16 y + 64, ) = 20 + 100 + 64</strong>, which is equivalent to <strong>(x + 10, ), ² + (y + 8, ), ² = 144</strong>. Therefore, the coordinates of the center of the circle are <strong>10 8</strong>.Choices A, C, and D are incorrect and may result from computational errors made when attempting to complete the squares or when identifying the coordinates of the center.",
hasFigure: false,
},
{
id: "249d3f80",
type: "spr",
questionHtml:
"Point <strong>O</strong> is the center of a circle. The measure of arc <strong>R S</strong> on this circle is <strong>100 °</strong>. What is the measure, in degrees, of its associated angle <strong>R O S</strong>?",
choices: [],
correctAnswer: "100",
explanation:
"The correct answer is <strong>100</strong>. It's given that point <strong>O</strong> is the center of a circle and the measure of arc <strong>R S</strong> on the circle is <strong>100 °</strong>. It follows that points <strong>R</strong> and <strong>S</strong> lie on the circle. Therefore, <strong>ModifyingAbove O R With bar</strong> and <strong>ModifyingAbove O S With bar</strong> are radii of the circle. A central angle is an angle formed by two radii of a circle, with its vertex at the center of the circle. Therefore, <strong>angle R O S</strong> is a central angle. Because the degree measure of an arc is equal to the measure of its associated central angle, it follows that the measure, in degrees, of <strong>angle R O S</strong> is <strong>100</strong>.",
hasFigure: false,
},
{
id: "24cec8d1",
type: "spr",
questionHtml:
"A circle has center <strong>O</strong>, and points <strong>R</strong> and <strong>S</strong> lie on the circle. In triangle <strong>O R S</strong>, the measure of <strong>angle R O S</strong> is <strong>88 °</strong>. What is the measure of <strong>angle R S O</strong>, in degrees? (Disregard the degree symbol when entering your answer.)",
choices: [],
correctAnswer: "46",
explanation:
"The correct answer is <strong>46</strong>. It's given that <strong>O</strong> is the center of a circle and that points <strong>R</strong> and <strong>S</strong> lie on the circle. Therefore, <strong>ModifyingAbove O R With bar</strong> and <strong>ModifyingAbove O S With bar</strong> are radii of the circle. It follows that <strong>O R = O S</strong>. If two sides of a triangle are congruent, then the angles opposite them are congruent. It follows that the angles <strong>angle R S O</strong> and <strong>angle O R S</strong>, which are across from the sides of equal length, are congruent. Let <strong>x °</strong> represent the measure of <strong>angle R S O</strong>. It follows that the measure of <strong>angle O R S</strong> is also <strong>x °</strong>. It's given that the measure of <strong>angle R O S</strong> is <strong>88 °</strong>. Because the sum of the measures of the interior angles of a triangle is <strong>180 °</strong>, the equation <strong>x ° + x ° + 88 ° = 180 °</strong>, or <strong>2 x + 88 = 180</strong>, can be used to find the measure of <strong>angle R S O</strong>. Subtracting <strong>88</strong> from both sides of this equation yields <strong>2 x = 92</strong>. Dividing both sides of this equation by <strong>2</strong> yields <strong>x = 46</strong>. Therefore, the measure of <strong>angle R S O</strong>, in degrees, is <strong>46</strong>.",
hasFigure: false,
},
{
id: "3e577e4a",
type: "mcq",
questionHtml:
"A circle in the xy-plane has its center at <strong>(4 6)</strong>. Line <strong>k</strong> is tangent to this circle at the point <strong>(7 7)</strong>. What is the slope of line <strong>k</strong>?",
choices: [
{ label: "A", text: "<strong>3</strong>" },
{ label: "B", text: "<strong>one third</strong>" },
{ label: "C", text: "<strong>one third</strong>" },
{ label: "D", text: "<strong>3</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. A line that's tangent to a circle is perpendicular to the radius of the circle at the point of tangency. It's given that the circle has its center at <strong>(4 6)</strong> and line <strong>k</strong> is tangent to the circle at the point <strong>(7 7)</strong>. The slope of a radius defined by the points <strong>(q, r)</strong> and <strong>(s, t)</strong> can be calculated as <strong>(t r) / (s q)</strong>. The points <strong>(7 7)</strong> and <strong>(4 6)</strong> define the radius of the circle at the point of tangency. Therefore, the slope of this radius can be calculated as <strong>((6) (7)) / ((4) (7))</strong>, or <strong>one third</strong>. If a line and a radius are perpendicular, the slope of the line must be the negative reciprocal of the slope of the radius. The negative reciprocal of <strong>one third</strong> is <strong>3</strong>. Thus, the slope of line <strong>k</strong> is <strong>3</strong>.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect. This is the slope of the radius of the circle at the point of tangency, not the slope of line <strong>k</strong>.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "69b0d79d",
type: "mcq",
questionHtml:
"Point O is the center of the circle above, and the measure of <strong>angle O A, B</strong> is <strong>30 °</strong>. If the length of <strong>O C</strong> is 18, what is the length of arc <strong>A, B</strong>?",
choices: [
{ label: "A", text: "<strong>9 π</strong>" },
{ label: "B", text: "<strong>12 π</strong>" },
{ label: "C", text: "<strong>15 π</strong>" },
{ label: "D", text: "<strong>18 π</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Because segments OA and OB are radii of the circle centered at point O, these segments have equal lengths. Therefore, triangle AOB is an isosceles triangle, where angles OAB and OBA are congruent base angles of the triangle. Its given that angle OAB measures <strong>30 °</strong>. Therefore, angle OBA also measures <strong>30 °</strong>. Let <strong>x °</strong> represent the measure of angle AOB. Since the sum of the measures of the three angles of any triangle is <strong>180 °</strong>, it follows that <strong>30 ° + 30 ° + x ° = 180 °</strong>, or <strong>60 ° + x ° = 180 °</strong>. Subtracting <strong>60 °</strong> from both sides of this equation yields <strong>x ° = 120 °</strong>, or <strong>the fraction 2 π over 3</strong> radians. Therefore, the measure of angle AOB, and thus the measure of arc <strong>A, B</strong>, is <strong>the fraction 2 π over 3</strong> radians. Since <strong>the O C</strong> is a radius of the given circle and its length is 18, the length of the radius of the circle is 18. Therefore, the length of arc <strong>A, B</strong> can be calculated as <strong>the fraction 2 π over 3, end fraction · 18</strong>, or <strong>12 π</strong>.Choices A, C, and D are incorrect and may result from conceptual or computational errors.",
hasFigure: true,
figureUrl: "/practice-images/69b0d79d_img1.png",
},
{
id: "76c73dbf",
type: "spr",
questionHtml:
"The graph of <strong>x² + x + y² + y = (199) / (2)</strong> in the xy-plane is a circle. What is the length of the circles radius?",
choices: [],
correctAnswer: "10",
explanation:
"The correct answer is <strong>10</strong>. It's given that the graph of <strong>x² + x + y² + y = (199) / (2)</strong> in the xy-plane is a circle. The equation of a circle in the xy-plane can be written in the form <strong>(x h)² + (y k)² = r²</strong>, where the coordinates of the center of the circle are <strong>(h, k)</strong> and the length of the radius of the circle is <strong>r</strong>. The term <strong>(x h)²</strong> in this equation can be obtained by adding the square of half the coefficient of <strong>x</strong> to both sides of the given equation to complete the square. The coefficient of <strong>x</strong> is <strong>1</strong>. Half the coefficient of <strong>x</strong> is <strong>one half</strong>. The square of half the coefficient of <strong>x</strong> is <strong>one fourth</strong>. Adding <strong>one fourth</strong> to each side of <strong>(x² + x) + (y² + y) = (199) / (2)</strong> yields <strong>(x² + x + one fourth) + (y² + y) = (199) / (2) + one fourth</strong>, or <strong>(x + one half)² + (y² + y) = (199) / (2) + one fourth</strong>. Similarly, the term <strong>(y k)²</strong> can be obtained by adding the square of half the coefficient of <strong>y</strong> to both sides of this equation, which yields <strong>(x + one half)² + (y² + y + one fourth) = (199) / (2) + one fourth + one fourth</strong>, or <strong>(x + one half)² + (y + one half)² = (199) / (2) + one fourth + one fourth</strong>. This equation is equivalent to <strong>(x + one half)² + (y + one half)² = 100</strong>, or <strong>(x + one half)² + (y + one half)² = 10²</strong>. Therefore, the length of the circle's radius is <strong>10</strong>.",
hasFigure: false,
},
{
id: "89661424",
type: "spr",
questionHtml:
"A circle in the xy-plane has its center at <strong>(5, 2)</strong> and has a radius of <strong>9</strong>. An equation of this circle is <strong>x² + y² + a x + b y + c = 0</strong>, where <strong>a</strong>, <strong>b</strong>, and <strong>c</strong> are constants. What is the value of <strong>c</strong>?",
choices: [],
correctAnswer: "-52",
explanation:
"The correct answer is <strong>52</strong>. The equation of a circle in the xy-plane with its center at <strong>(h, k)</strong> and a radius of <strong>r</strong> can be written in the form <strong>(x h)² + (y k)² = r²</strong>. It's given that a circle in the xy-plane has its center at <strong>(5, 2)</strong> and has a radius of <strong>9</strong>. Substituting <strong>5</strong> for <strong>h</strong>, <strong>2</strong> for <strong>k</strong>, and <strong>9</strong> for <strong>r</strong> in the equation <strong>(x h)² + (y k)² = r²</strong> yields <strong>(x (5))² + (y 2)² = 9²</strong>, or <strong>(x + 5)² + (y 2)² = 81</strong>. It's also given that an equation of this circle is <strong>x² + y² + a x + b y + c = 0</strong>, where <strong>a</strong>, <strong>b</strong>, and <strong>c</strong> are constants. Therefore, <strong>(x + 5)² + (y 2)² = 81</strong> can be rewritten in the form <strong>x² + y² + a x + b y + c = 0</strong>. The equation <strong>(x + 5)² + (y 2)² = 81</strong>, or <strong>(x + 5) (x + 5) + (y 2) (y 2) = 81</strong>, can be rewritten as <strong>x² + 5 x + 5 x + 25 + y² 2 y 2 y + 4 = 81</strong>. Combining like terms on the left-hand side of this equation yields <strong>x² + y² + 10 x 4 y + 29 = 81</strong>. Subtracting <strong>81</strong> from both sides of this equation yields <strong>x² + y² + 10 x 4 y 52 = 0</strong>, which is equivalent to <strong>x² + y² + 10 x + (4) y + (52) = 0</strong>. This equation is in the form <strong>x² + y² + a x + b y + c = 0</strong>. Therefore, the value of <strong>c</strong> is <strong>52</strong>.",
hasFigure: false,
},
{
id: "981275d2",
type: "mcq",
questionHtml:
"In the xy-plane, the graph of the equation above is a circle. Point P is on the circle and has coordinates <strong>10 5</strong>. If <strong>P Q</strong> is a diameter of the circle, what are the coordinates of point Q ?",
choices: [
{ label: "A", text: "<strong>2 5</strong>" },
{ label: "B", text: "<strong>6 1</strong>" },
{ label: "C", text: "<strong>6 5</strong>" },
{ label: "D", text: "<strong>6 9</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The standard form for the equation of a circle is <strong>(x h, ), ² + (y k, ), ² = r²</strong>, where <strong>the ordered pair h, k</strong> are the coordinates of the center and r is the length of the radius. According to the given equation, the center of the circle is <strong>6 5</strong>. Let <strong>x sub 1, y sub 1</strong> represent the coordinates of point Q. Since point P <strong>10 5</strong> and point Q <strong>x sub 1, y sub 1</strong> are the endpoints of a diameter of the circle, the center <strong>with coordinates 6 5</strong> lies on the diameter, halfway between P and Q. Therefore, the following relationships hold: <strong>the fraction with numerator x sub 1 + 10, and denominator 2 = 6</strong> and <strong>the fraction with numerator y sub 1 + 5, and denominator 2 = 5</strong>. Solving the equations for <strong>x sub 1</strong> and <strong>y sub 1</strong>, respectively, yields <strong>x sub 1 = 2</strong> and <strong>y sub 1 = 5</strong>. Therefore, the coordinates of point Q are <strong>2 5</strong>.Alternate approach: Since point P <strong>10 5</strong> on the circle and the center of the circle <strong>6 5</strong> have the same y-coordinate, it follows that the radius of the circle is <strong>10 6 = 4</strong>. In addition, the opposite end of the diameter <strong>P Q</strong> must have the same y-coordinate as P and be 4 units away from the center. Hence, the coordinates of point Q must be <strong>2 5</strong>.<br>Choices B and D are incorrect because the points given in these choices lie on a diameter that is perpendicular to the diameter <strong>P Q</strong>. If either of these points were point Q, then <strong>P Q</strong> would not be the diameter of the circle. Choice C is incorrect because <strong>6 5</strong> is the center of the circle and does not lie on the circle.",
hasFigure: false,
},
{
id: "9acd101f",
type: "mcq",
questionHtml:
"The equation <strong>x² + (y 1)² = 49</strong> represents circle A. Circle B is obtained by shifting circle A down <strong>2</strong> units in the xy-plane. Which of the following equations represents circle B?",
choices: [
{ label: "A", text: "<strong>(x 2)² + (y 1)² = 49</strong>" },
{ label: "B", text: "<strong>x² + (y 3)² = 49</strong>" },
{ label: "C", text: "<strong>(x + 2)² + (y 1)² = 49</strong>" },
{ label: "D", text: "<strong>x² + (y + 1)² = 49</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The graph in the xy-plane of an equation of the form <strong>(x h)² + (y k)² = r²</strong> is a circle with center <strong>(h, k)</strong> and a radius of length <strong>r</strong>. It's given that circle A is represented by <strong>x² + (y 1)² = 49</strong>, which can be rewritten as <strong>x² + (y 1)² = 7²</strong>. Therefore, circle A has center <strong>(0, 1)</strong> and a radius of length <strong>7</strong>. Shifting circle A down two units is a rigid vertical translation of circle A that does not change its size or shape. Since circle B is obtained by shifting circle A down two units, it follows that circle B has the same radius as circle A, and for each point <strong>(x, y)</strong> on circle A, the point <strong>(x, y 2)</strong> lies on circle B. Moreover, if <strong>(h, k)</strong> is the center of circle A, then <strong>(h, k 2)</strong> is the center of circle B. Therefore, circle B has a radius of <strong>7</strong> and the center of circle B is <strong>(0, 1 2)</strong>, or <strong>(0 1)</strong>. Thus, circle B can be represented by the equation <strong>x² + (y + 1)² = 7²</strong>, or <strong>x² + (y + 1)² = 49</strong>.<br>Choice A is incorrect. This is the equation of a circle obtained by shifting circle A right <strong>2</strong> units.<br>Choice B is incorrect. This is the equation of a circle obtained by shifting circle A up <strong>2</strong> units.<br>Choice C is incorrect. This is the equation of a circle obtained by shifting circle A left <strong>2</strong> units.",
hasFigure: false,
},
{
id: "9d159400",
type: "mcq",
questionHtml:
"Which of the following equations represents a circle in the xy-plane that intersects the y-axis at exactly one point?",
choices: [
{ label: "A", text: "<strong>(x 8)² + (y 8)² = 16</strong>" },
{ label: "B", text: "<strong>(x 8)² + (y 4)² = 16</strong>" },
{ label: "C", text: "<strong>(x 4)² + (y 9)² = 16</strong>" },
{ label: "D", text: "<strong>x² + (y 9)² = 16</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The graph of the equation <strong>(x h)² + (y k)² = r²</strong> in the xy-plane is a circle with center <strong>(h, k)</strong> and a radius of length <strong>r</strong>. The radius of a circle is the distance from the center of the circle to any point on the circle. If a circle in the xy-plane intersects the y-axis at exactly one point, then the perpendicular distance from the center of the circle to this point on the y-axis must be equal to the length of the circle's radius. It follows that the x-coordinate of the circle's center must be equivalent to the length of the circle's radius. In other words, if the graph of <strong>(x h)² + (y k)² = r²</strong> is a circle that intersects the y-axis at exactly one point, then <strong>r = |h|</strong> must be true. The equation in choice C is <strong>(x 4)² + (y 9)² = 16</strong>, or <strong>(x 4)² + (y 9)² = 4²</strong>. This equation is in the form <strong>(x h)² + (y k)² = r²</strong>, where <strong>h = 4</strong>, <strong>k = 9</strong>, and <strong>r = 4</strong>, and represents a circle in the xy-plane with center <strong>(4, 9)</strong> and radius of length <strong>4</strong>. Substituting <strong>4</strong> for <strong>r</strong> and <strong>4</strong> for <strong>h</strong> in the equation <strong>r = |h|</strong> yields <strong>4 = |4|</strong>, or <strong>4 = 4</strong>, which is true. Therefore, the equation in choice C represents a circle in the xy-plane that intersects the y-axis at exactly one point. <br>Choice A is incorrect. This is the equation of a circle that does not intersect the y-axis at any point.<br>Choice B is incorrect. This is an equation of a circle that intersects the x-axis, not the y-axis, at exactly one point.<br>Choice D is incorrect. This is the equation of a circle with the center located on the y-axis and thus intersects the y-axis at exactly two points, not exactly one point.",
hasFigure: false,
},
{
id: "9e44284b",
type: "mcq",
questionHtml:
"In the xy-plane, the graph of <strong>2 x² 6 x + 2 y² + 2 y = 45</strong> is a circle. What is the radius of the circle?",
choices: [
{ label: "A", text: "5" },
{ label: "B", text: "6.5" },
{ label: "C", text: "<strong>√ 40</strong>" },
{ label: "D", text: "<strong>√ 50</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. One way to find the radius of the circle is to rewrite the given equation in standard form, <strong>(x h, ), ² + (y k, ), ² = r²</strong>, where <strong>the ordered pair h, k</strong> is the center of the circle and the radius of the circle is r. To do this, divide the original equation, <strong>2 x² 6 x + 2 y² + 2 y = 45</strong>, by 2 to make the leading coefficients of <strong>x²</strong> and <strong>y²</strong> each equal to 1: <strong>as follows: x² 3 x + y² + y = 22 . 5</strong>. Then complete the square to put the equation in standard form. To do so, first rewrite <strong>x² 3 x + y² + y = 22 . 5</strong> as <strong>(x² 3 x + 2 . 2 5, ) 2 . 2 5 + (y² + y + 0 . 2 5, ) 0 . 2 5 = 22 . 5</strong>. Second, add 2.25 and 0.25 to both sides of the equation: <strong>(x² 3 x + 2 . 2 5, ) + (y² + y + 0 . 2 5, ) = 25</strong>. Since <strong>x² 3 x + 2 . 2 5 = (x 1 . 5, ), ²</strong>, <strong>y² + y + 0 . 2 5 = (y + 0 . 5, ), ²</strong>, and <strong>25 = 5²</strong>, it follows that <strong>(x 1 . 5, ), ² + (y + 0 . 5, ), ² = 5²</strong>. Therefore, the radius of the circle is 5.Choices B, C, and D are incorrect and may be the result of errors in manipulating the equation or of a misconception about the standard form of the equation of a circle in the xy-plane.",
hasFigure: false,
},
{
id: "ab176ad6",
type: "spr",
questionHtml:
"The equation <strong>(x + 6, ), ² + (y + 3, ), ² = 121</strong> defines a circle in the xyplane. What is the radius of the circle?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 11. A circle with equation <strong>(x a, ), ² + (y b, ), ² = r²</strong>, where a, b, and r are constants, has center <strong>with coordinates a, , b</strong> and radius r. Therefore, the radius of the given circle is <strong>the √ 121</strong>, or 11.",
hasFigure: false,
},
{
id: "acd30391",
type: "mcq",
questionHtml:
"A circle in the xy-plane has equation <strong>(x + 3, ), ² + (y 1, ), ² = 25</strong>. Which of the following points does NOT lie in the interior of the circle?",
choices: [
{ label: "A", text: "<strong>7, 3</strong>" },
{ label: "B", text: "<strong>3, 1</strong>" },
{ label: "C", text: "<strong>zero, zero</strong>" },
{ label: "D", text: "<strong>3, 2</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The circle with equation <strong>(x + 3, ), ² + (y 1, ), ² = 25</strong> has center <strong>with coordinates 3, 1</strong> and radius 5. For a point to be inside of the circle, the distance from that point to the center must be less than the radius, 5. The distance between <strong>3, 2</strong> and <strong>3, 1</strong> is <strong>the √, (3 3, ), ² + (1 2, ), ², end root = the √, (6, ), ² + (1, ), ², end root, which = the √ 37</strong>, which is greater than 5. Therefore, <strong>3, 2</strong> does NOT lie in the interior of the circle.Choice A is incorrect. The distance between <strong>7, 3</strong> and <strong>3, 1</strong> is <strong>the √, (7 + 3, ), ² + (3 1, ), ², end root = the √, (4, ), ² + (2, ), ², end root, which = the √ 20</strong>, which is less than 5, and therefore <strong>7, 3</strong> lies in the interior of the circle. Choice B is incorrect because it is the center of the circle. Choice C is incorrect because the distance between <strong>0, 0</strong> and <strong>3, 1</strong> is <strong>the √, (0 + 3, ), ² + (0 1, ), ², end root = the √, (3, ), ² + (1, ), ², end root, which = the √ 8</strong>, which is less than 5, and therefore <strong>0, 0</strong> in the interior of the circle.",
hasFigure: false,
},
{
id: "b0a72bdc",
type: "mcq",
questionHtml:
"What is the diameter of the circle in the xy-plane with equation <strong>(x 5)² + (y 3)² = 16</strong>?",
choices: [
{ label: "A", text: "<strong>4</strong>" },
{ label: "B", text: "<strong>8</strong>" },
{ label: "C", text: "<strong>16</strong>" },
{ label: "D", text: "<strong>32</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The standard form of an equation of a circle in the xy-plane is <strong>(x h)² + (y k)² = r²</strong>, where the coordinates of the center of the circle are <strong>(h, k)</strong> and the length of the radius of the circle is <strong>r</strong>. For the circle in the xy-plane with equation <strong>(x 5)² + (y 3)² = 16</strong>, it follows that <strong>r² = 16</strong>. Taking the square root of both sides of this equation yields <strong>r = 4</strong> or <strong>r = 4</strong>. Because <strong>r</strong> represents the length of the radius of the circle and this length must be positive, <strong>r = 4</strong>. Therefore, the radius of the circle is <strong>4</strong>. The diameter of a circle is twice the length of the radius of the circle. Thus, <strong>2 (4)</strong> yields <strong>8</strong>. Therefore, the diameter of the circle is <strong>8</strong>.<br>Choice A is incorrect. This is the radius of the circle. <br>Choice C is incorrect. This is the square of the radius of the circle. <br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "b8a225ff",
type: "spr",
questionHtml:
"Circle A in the xy-plane has the equation <strong>(x + 5)² + (y 5)² = 4</strong>. Circle B has the same center as circle A. The radius of circle B is two times the radius of circle A. The equation defining circle B in the xy-plane is <strong>(x + 5)² + (y 5)² = k</strong>, where <strong>k</strong> is a constant. What is the value of <strong>k</strong>?",
choices: [],
correctAnswer: "16",
explanation:
"The correct answer is <strong>16</strong>. An equation of a circle in the xy-plane can be written as <strong>(x t)² + (y u)² = r²</strong>, where the center of the circle is <strong>(t, u)</strong> , the radius of the circle is <strong>r</strong>, and where <strong>t</strong>, <strong>u</strong>, and <strong>r</strong> are constants. Its given that the equation of circle A is <strong>(x + 5)² + (y 5)² = 4</strong>, which is equivalent to <strong>(x + 5)² + (y 5)² = 2²</strong>. Therefore, the center of circle A is <strong>(5, 5)</strong> and the radius of circle A is <strong>2</strong>. Its given that circle B has the same center as circle A and that the radius of circle B is two times the radius of circle A. Therefore, the center of circle B is <strong>(5, 5)</strong> and the radius of circle B is <strong>2 (2)</strong>, or <strong>4</strong>. Substituting <strong>5</strong> for <strong>t</strong>, <strong>5</strong> for <strong>u</strong>, and <strong>4</strong> for <strong>r</strong> into the equation <strong>(x t)² + (y u)² = r²</strong>  yields <strong>(x + 5)² + (y 5)² = 4²</strong>, which is equivalent to <strong>(x + 5)² + (y 5)² = 16</strong>. It follows that the equation of circle B in the xy-plane is <strong>(x + 5)² + (y 5)² = 16</strong>. Therefore, the value of <strong>k</strong> is <strong>16</strong>.",
hasFigure: false,
},
{
id: "c8345903",
type: "mcq",
questionHtml:
"The circle above has center O, the length of arc <strong>A, D C</strong> is <strong>5 π</strong>, and <strong>x = 100</strong>. What is the length of arc <strong>A, B C</strong> ?",
choices: [
{ label: "A", text: "<strong>9 π</strong>" },
{ label: "B", text: "<strong>13 π</strong>" },
{ label: "C", text: "<strong>18 π</strong>" },
{ label: "D", text: "<strong>13 halves π</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The ratio of the lengths of two arcs of a circle is equal to the ratio of the measures of the central angles that subtend the arcs. Its given that arc <strong>A D C</strong> is subtended by a central angle with measure 100°. Since the sum of the measures of the angles about a point is 360°, it follows that arc <strong>A B C</strong> is subtended by a central angle with measure <strong>360 ° 100 ° = 260 °</strong>. If s is the length of arc <strong>A B C</strong>, then s must satisfy the ratio <strong>the fraction s over 5 π, end fraction = the fraction 260 over 100</strong>. Reducing the fraction <strong>260 over 100</strong> to its simplest form gives <strong>the fraction 13 over 5</strong>. Therefore, <strong>the fraction s over 5 π, end fraction = the fraction 13 over 5</strong>. Multiplying both sides of <strong>the fraction s over 5 π, end fraction = the fraction 13 over 5</strong> by <strong>5 π</strong> yields <strong>s = 13 π</strong>.Choice A is incorrect. This is the length of an arc consisting of exactly half of the circle, but arc <strong>A B C</strong> is greater than half of the circle. Choice C is incorrect. This is the total circumference of the circle. Choice D is incorrect. This is half the length of arc <strong>A B C</strong>, not its full length.",
hasFigure: true,
figureUrl: "/practice-images/c8345903_img1.png",
},
{
id: "ca2235f6",
type: "mcq",
questionHtml:
"A circle has center <em>(expression)</em>, and points <em>(expression)</em> and <em>(expression)</em> lie on the circle. The measure of arc <em>(expression)</em> is <em>(expression)</em> and the length of arc <em>(expression)</em> is <em>(expression)</em> inches. What is the circumference, in inches, of the circle?",
choices: [
{ label: "A", text: "<em>(expression)</em>" },
{ label: "B", text: "<em>(expression)</em>" },
{ label: "C", text: "<em>(expression)</em>" },
{ label: "D", text: "<em>(expression)</em>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Its given that the measure of arc <strong>A B</strong> is <strong>45 °</strong> and the length of arc <strong>A B</strong> is <strong>3 inches</strong>. The arc measure of the full circle is <strong>360 °</strong>. If <strong>x</strong> represents the circumference, in inches, of the circle, it follows that <strong>(45 °) / (360 °) = (3 inches) / (x inches)</strong>. This equation is equivalent to <strong>(45) / (360) = (3) / (x)</strong>, or <strong>one eighth = (3) / (x)</strong>. Multiplying both sides of this equation by <strong>8 x</strong> yields <strong>1 (x) = 3 (8)</strong>, or <strong>x = 24</strong>. Therefore, the circumference of the circle is <strong>24 inches</strong>.<br>Choice A is incorrect. This is the length of arc <strong>A B</strong>.<br>Choice B is incorrect and may result from multiplying the length of arc <strong>A B</strong> by <strong>2</strong>.<br>Choice C is incorrect and may result from squaring the length of arc <strong>A B</strong>.",
hasFigure: false,
},
{
id: "e80d62c6",
type: "mcq",
questionHtml:
"The equation <strong>x² + (y 2)² = 36</strong> represents circle A. Circle B is obtained by shifting circle A down <strong>4</strong> units in the xy-plane. Which of the following equations represents circle B?",
choices: [
{ label: "A", text: "<strong>x² + (y + 2)² = 36</strong>" },
{ label: "B", text: "<strong>x² + (y 6)² = 36</strong>" },
{ label: "C", text: "<strong>(x 4)² + (y 2)² = 36</strong>" },
{ label: "D", text: "<strong>(x + 4)² + (y 2)² = 36</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The standard form of an equation of a circle in the xy-plane is <strong>(x h)² + (y k)² = r²</strong>, where the coordinates of the center of the circle are <strong>(h, k)</strong> and the length of the radius of the circle is <strong>r</strong>. The equation of circle A, <strong>x² + (y 2)² = 36</strong>, can be rewritten as <strong>(x 0)² + (y 2)² = 6²</strong>. Therefore, the center of circle A is at <strong>(0, 2)</strong> and the length of the radius of circle A is <strong>6</strong>. If circle A is shifted down <strong>4</strong> units, the y-coordinate of its center will decrease by <strong>4</strong>; the radius of the circle and the x-coordinate of its center will not change. Therefore, the center of circle B is at <strong>(0, 2 4)</strong>, or <strong>(0 2)</strong>, and its radius is <strong>6</strong>. Substituting <strong>0</strong> for <strong>h</strong>, <strong>2</strong> for <strong>k</strong>, and <strong>6</strong> for <strong>r</strong> in the equation <strong>(x h)² + (y k)² = r²</strong> yields <strong>(x 0)² + (y (2))² = (6)²</strong>, or <strong>x² + (y + 2)² = 36</strong>. Therefore, the equation <strong>x² + (y + 2)² = 36</strong> represents circle B.<br>Choice B is incorrect. This equation represents a circle obtained by shifting circle A up, rather than down, <strong>4</strong> units.<br>Choice C is incorrect. This equation represents a circle obtained by shifting circle A right, rather than down, <strong>4</strong> units.<br>Choice D is incorrect. This equation represents a circle obtained by shifting circle A left, rather than down, <strong>4</strong> units.",
hasFigure: false,
},
{
id: "ebbf23ae",
type: "spr",
questionHtml:
"A circle in the xy-plane has a diameter with endpoints <strong>(2, 4)</strong> and <strong>(2, 14)</strong>. An equation of this circle is <strong>(x 2)² + (y 9)² = r²</strong>, where <strong>r</strong> is a positive constant. What is the value of <strong>r</strong>?",
choices: [],
correctAnswer: "5",
explanation:
"The correct answer is <strong>5</strong>. The standard form of an equation of a circle in the xy-plane is <strong>(x h)² + (y k)² = r²</strong>, where <strong>h</strong>, <strong>k</strong>, and <strong>r</strong> are constants, the coordinates of the center of the circle are <strong>(h, k)</strong>, and the length of the radius of the circle is <strong>r</strong>. Its given that an equation of the circle is <strong>(x 2)² + (y 9)² = r²</strong>. Therefore, the center of this circle is <strong>(2, 9)</strong>. Its given that the endpoints of a diameter of the circle are <strong>(2, 4)</strong> and <strong>(2, 14)</strong>. The length of the radius is the distance from the center of the circle to an endpoint of a diameter of the circle, which can be found using the distance formula, <strong>√((x 1 x 2)² + (y 1 y 2)²)</strong>. Substituting the center of the circle <strong>(2, 9)</strong> and one endpoint of the diameter <strong>(2, 4)</strong> in this formula gives a distance of <strong>√((2 2)² + (9 4)²)</strong>, or <strong>√(0² + 5²)</strong>, which is equivalent to <strong>5</strong>. Since the distance from the center of the circle to an endpoint of a diameter is <strong>5</strong>, the value of <strong>r</strong> is <strong>5</strong>.",
hasFigure: false,
},
{
id: "fb58c0db",
type: "spr",
questionHtml:
"Points A and B lie on a circle with radius 1, and arc <strong>A, B</strong> has length <strong>π over 3</strong>. What fraction of the circumference of the circle is the length of arc <strong>A, B</strong> ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is <strong>one sixth</strong>. The circumference, C, of a circle is <strong>C = 2 π, r</strong>, where r is the length of the radius of the circle. For the given circle with a radius of 1, the circumference is <strong>C = 2 π · 1</strong>, or <strong>C = 2 π</strong>. To find what fraction of the circumference the length of arc <strong>A, B</strong> is, divide the length of the arc by the circumference, which gives <strong>the fraction π over 3, end fraction ÷ 2 π</strong>. This division can be represented by <strong>the fraction π over 3, end fraction · the fraction 1 over 2 π, end fraction = one sixth</strong>. Note that 1/6, .1666, .1667, 0.166, and 0.167 are examples of ways to enter a correct answer.",
hasFigure: false,
},
];

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,236 @@
import { type PracticeQuestion } from "../../types/lesson";
export const EVAL_STATS_EASY: PracticeQuestion[] = [
{
id: "82dfb646",
type: "mcq",
questionHtml:
"A market researcher selected 200 people at random from a group of people who indicated that they liked a certain book. The 200 people were shown a movie based on the book and then asked whether they liked or disliked the movie. Of those surveyed, 95% said they disliked the movie. Which of the following inferences can appropriately be drawn from this survey result?",
choices: [
{
label: "A",
text: "At least 95% of people who go see movies will dislike this movie.",
},
{
label: "B",
text: "At least 95% of people who read books will dislike this movie.",
},
{
label: "C",
text: "Most people who dislike this book will like this movie.",
},
{
label: "D",
text: "Most people who like this book will dislike this movie.",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. The sample was selected from a group of people who indicated that they liked the book. It is inappropriate to generalize the result of the survey beyond the population from which the participants were selected. Choice D is the most appropriate inference from the survey results because it describes a conclusion about people who liked the book, and the results of the survey indicate that most people who like the book disliked the movie.Choices A, B, and C are incorrect because none of these inferences can be drawn from the survey results. Choices A and B need not be true. The people surveyed all liked the book on which the movie was based, which is not necessarily true of all people who go see movies or all people who read books. Thus, the people surveyed are not representative of all people who go see movies or all people who read books. Therefore, the results of this survey cannot appropriately be extended to at least 95% of people who go see movies or to at least 95% of people who read books. Choice C need not be true because the sample includes only people who liked the book, and so the results do not extend to people who dislike the book.",
hasFigure: false,
},
{
id: "9bf4c545",
type: "mcq",
questionHtml:
"The members of a city council wanted to assess the opinions of all city residents about converting an open field into a dog park. The council surveyed a sample of 500 city residents who own dogs. The survey showed that the majority of those sampled were in favor of the dog park. Which of the following is true about the city councils survey?",
choices: [
{
label: "A",
text: "It shows that the majority of city residents are in favor of the dog park.",
},
{
label: "B",
text: "The survey sample should have included more residents who are dog owners.",
},
{
label: "C",
text: "The survey sample should have consisted entirely of residents who do not own dogs.",
},
{
label: "D",
text: "The survey sample is biased because it is not representative of all city residents.",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. The members of the city council wanted to assess opinions of all city residents. To gather an unbiased sample, the council should have used a random sampling design to select subjects from all city residents. The given survey introduced a sampling bias because the 500 city residents surveyed were all dog owners. This sample is not representative of all city residents because not all city residents are dog owners.Choice A is incorrect because when the sampling method isnt random, there is no guarantee that the survey results will be reliable; hence, they cannot be generalized to the entire population. Choice B is incorrect because a larger sample of residents who are dog owners would not correct the sampling bias. Choice C is incorrect because a survey sample of entirely nondog owners would likely have a biased opinion, just as a sample of dog owners would likely have a biased opinion.",
hasFigure: false,
},
];
export const EVAL_STATS_MEDIUM: PracticeQuestion[] = [
{
id: "37930b2a",
type: "mcq",
questionHtml:
"Residents of a town were surveyed to determine whether they are satisfied with the concession stand at the local park. A random sample of 200 residents was selected. All 200 responded, and 87% said they are satisfied. Based on this information, which of the following statements must be true?I. Of all the town residents, 87% would say they are satisfied with the concession stand at the local park.<br><br>II. If another random sample of 200 residents were surveyed, 87% would say they are satisfied.",
choices: [
{ label: "A", text: "Neither" },
{ label: "B", text: "I only" },
{ label: "C", text: "II only" },
{ label: "D", text: "I and II" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The purpose of surveying a random sample of residents is to approximate the percent of the town residents that are satisfied with the concession stand. The sample doesnt necessarily get the same result as surveying every resident of the town, nor would another sample necessarily have identical results. Therefore, although its possible that either statement I or statement II could prove true by surveying every resident of the town, these statements cannot be proven true solely based on the results of the sample.Choice B is incorrect because surveying a sample of the town residents may not have the same result as surveying all the town residents. Choices C and D are incorrect because surveying a different sample of residents could yield different results.",
hasFigure: false,
},
{
id: "642519d7",
type: "mcq",
questionHtml:
"A polling agency recently surveyed 1,000 adults who were selected at random from a large city and asked each of the adults, “Are you satisfied with the quality of air in the city?” Of those surveyed, 78 percent responded that they were satisfied with the quality of air in the city. Based on the results of the survey, which of the following statements must be true?Of all adults in the city, 78 percent are satisfied with the quality of air in the city.<br> If another 1,000 adults selected at random from the city were surveyed, 78 percent of them would report they are satisfied with the quality of air in the city.<br> If 1,000 adults selected at random from a different city were surveyed, 78 percent of them would report they are satisfied with the quality of air in the city.",
choices: [
{ label: "A", text: "None" },
{ label: "B", text: "II only" },
{ label: "C", text: "I and II only" },
{ label: "D", text: "I and III only" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Statement I need not be true. The fact that 78% of the 1,000 adults who were surveyed responded that they were satisfied with the air quality in the city does not mean that the exact same percentage of all adults in the city will be satisfied with the air quality in the city. Statement II need not be true because random samples, even when they are of the same size, are not necessarily identical with regard to percentages of people in them who have a certain opinion. Statement III need not be true for the same reason that statement II need not be true: results from different samples can vary. The variation may be even bigger for this sample since it would be selected from a different city. Therefore, none of the statements must be true.Choices B, C, and D are incorrect because none of the statements must be true.",
hasFigure: false,
},
{
id: "b4f5a7ca",
type: "mcq",
questionHtml:
"A survey was conducted using a sample of history professors selected at random from the California State Universities. The professors surveyed were asked to name the publishers of their current texts. What is the largest population to which the results of the survey can be generalized?",
choices: [
{ label: "A", text: "All professors in the United States" },
{ label: "B", text: "All history professors in the United States" },
{
label: "C",
text: "All history professors at all California State Universities",
},
{
label: "D",
text: "All professors at all California State Universities",
},
],
correctAnswer: "C",
explanation:
"Choice C is correct. Selecting a sample at random when conducting a survey allows the results to be generalized to the population from which the sample was selected, but not beyond this population. In this situation, the population that the sample was selected from is history professors from the California State Universities. Therefore, the largest population to which the results of the survey can be generalized is all history professors at all California State Universities.Choices A, B, and D are incorrect. Since the sample was selected at random from history professors from the California State Universities, the results of the survey cant be generalized to all professors in the United States, all history professors in the United States, or all professors at all California State Universities. All three of these populations may use different texts and therefore may name different publishers.",
hasFigure: false,
},
];
export const EVAL_STATS_HARD: PracticeQuestion[] = [
{
id: "1ea09200",
type: "mcq",
questionHtml:
"A sample of 40 fourth-grade students was selected at random from a certain school. The 40 students completed a survey about the morning announcements, and 32 thought the announcements were helpful. Which of the following is the largest population to which the results of the survey can be applied?",
choices: [
{ label: "A", text: "The 40 students who were surveyed" },
{ label: "B", text: "All fourth-grade students at the school" },
{ label: "C", text: "All students at the school" },
{
label: "D",
text: "All fourth-grade students in the county in which the school is located",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. Selecting a sample of a reasonable size at random to use for a survey allows the results from that survey to be applied to the population from which the sample was selected, but not beyond this population. In this case, the population from which the sample was selected is all fourth-grade students at a certain school. Therefore, the results of the survey can be applied to all fourth-grade students at the school.Choice A is incorrect. The results of the survey can be applied to the 40 students who were surveyed. However, this isnt the largest group to which the results of the survey can be applied. Choices C and D are incorrect. Since the sample was selected at random from among the fourth-grade students at a certain school, the results of the survey cant be applied to other students at the school or to other fourth-grade students who werent represented in the survey results. Students in other grades in the school or other fourth-grade students in the country may feel differently about announcements than the fourth-grade students at the school.",
hasFigure: false,
},
{
id: "4a422e3e",
type: "mcq",
questionHtml:
"To determine the mean number of children per household in a community, Tabitha surveyed 20 families at a playground. For the 20 families surveyed, the mean number of children per household was 2.4. Which of the following statements must be true?",
choices: [
{
label: "A",
text: "The mean number of children per household in the community is 2.4.",
},
{
label: "B",
text: "A determination about the mean number of children per household in the community should not be made because the sample size is too small.",
},
{
label: "C",
text: "The sampling method is flawed and may produce a biased estimate of the mean number of children per household in the community.",
},
{
label: "D",
text: "The sampling method is not flawed and is likely to produce an unbiased estimate of the mean number of children per household in the community.",
},
],
correctAnswer: "C",
explanation:
"Choice C is correct. In order to use a sample mean to estimate the mean for a population, the sample must be representative of the population (for example, a simple random sample). In this case, Tabitha surveyed 20 families in a playground. Families in the playground are more likely to have children than other households in the community. Therefore, the sample isnt representative of the population. Hence, the sampling method is flawed and may produce a biased estimate.Choices A and D are incorrect because they incorrectly assume the sampling method is unbiased. Choice B is incorrect because a sample of size 20 could be large enough to make an estimate if the sample had been representative of all the families in the community.",
hasFigure: false,
},
{
id: "7ce2830a",
type: "mcq",
questionHtml:
"A psychologist designed and conducted a study to determine whether playing a certain educational game increases middle school students accuracy in adding fractions. For the study, the psychologist chose a random sample of 35 students from all of the students at one of the middle schools in a large city. The psychologist found that students who played the game showed significant improvement in accuracy when adding fractions. What is the largest group to which the results of the study can be generalized?",
choices: [
{ label: "A", text: "The 35 students in the sample" },
{ label: "B", text: "All students at the school" },
{ label: "C", text: "All middle school students in the city" },
{ label: "D", text: "All students in the city" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The largest group to which the results of a study can be generalized is the population from which the random sample was chosen. In this case, the psychologist chose a random sample from all students at one particular middle school. Therefore, the largest group to which the results can be generalized is all the students at the school.Choice A is incorrect because this isnt the largest group the results can be generalized to. Choices C and D are incorrect because these groups are larger than the population from which the random sample was chosen. Therefore, the sample isnt representative of these groups.",
hasFigure: false,
},
{
id: "7d68096f",
type: "mcq",
questionHtml:
"A trivia tournament organizer wanted to study the relationship between the number of points a team scores in a trivia round and the number of hours that a team practices each week. For the study, the organizer selected <strong>55</strong> teams at random from all trivia teams in a certain tournament. The table displays the information for the <strong>40</strong> teams in the sample that practiced for at least <strong>3</strong> hours per week.<br><br>Hours practiced<br>Number of points per round<br><br>6 to 13 points<br>14 or more points<br>Total<br><br>3 to 5 hours<br><strong>6</strong><br><strong>4</strong><br><strong>10</strong><br><br>More than 5 hours<br><strong>4</strong><br><strong>26</strong><br><strong>30</strong><br><br>Total<br><strong>10</strong><br><strong>30</strong><br><strong>40</strong><br><br>Which of the following is the largest population to which the results of the study can be generalized?",
choices: [
{
label: "A",
text: "All trivia teams in the tournament that scored <strong>14</strong> or more points in the round",
},
{
label: "B",
text: "The <strong>55</strong> trivia teams in the sample",
},
{
label: "C",
text: "The <strong>40</strong> trivia teams in the sample that practiced for at least <strong>3</strong> hours per week",
},
{ label: "D", text: "All trivia teams in the tournament" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. It's given that the organizer selected <strong>55</strong> teams at random from all trivia teams in the tournament. A table is also given displaying the information for the <strong>40</strong> teams in the sample that practiced for at least <strong>3</strong> hours per week. Selecting a sample of a reasonable size at random to use for a survey allows the results from that survey to be applied to the population from which the sample was selected, but not beyond this population. Thus, only the sampling method information is necessary to determine the largest population to which the results of the study can be generalized. Since the organizer selected the sample at random from all trivia teams in the tournament, the largest population to which the results of the study can be generalized is all trivia teams in the tournament.<br>Choice A is incorrect. The sample was selected at random from all trivia teams in the tournament, not just from the teams that scored an average of <strong>14</strong> or more points per round.<br>Choice B is incorrect. If a study uses a sample selected at random from a population, the results of the study can be generalized to the population, not just the sample.<br>Choice C is incorrect. If a study uses a sample selected at random from a population, the results of the study can be generalized to the population, not just a subset of the sample.",
hasFigure: false,
},
{
id: "aa43b41f",
type: "mcq",
questionHtml:
"Near the end of a US cable news show, the host invited viewers to respond to a poll on the shows website that asked, “Do you support the new federal policy discussed during the show?” At the end of the show, the host reported that 28% responded “Yes,” and 70% responded “No.” Which of the following best explains why the results are unlikely to represent the sentiments of the population of the United States?",
choices: [
{
label: "A",
text: "The percentages do not add up to 100%, so any possible conclusions from the poll are invalid.",
},
{
label: "B",
text: "Those who responded to the poll were not a random sample of the population of the United States.",
},
{
label: "C",
text: "There were not 50% “Yes” responses and 50% “No” responses.",
},
{
label: "D",
text: "The show did not allow viewers enough time to respond to the poll.",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. In order for the poll results from a sample of a population to represent the entire population, the sample must be representative of the population. A sample that is randomly selected from a population is more likely than a sample of the type described to represent the population. In this case, the people who responded were people with access to cable television and websites, which arent accessible to the entire population. Moreover, the people who responded also chose to watch the show and respond to the poll. The people who made these choices arent representative of the entire population of the United States because they were not a random sample of the population of the United States.Choices A, C, and D are incorrect because they present reasons unrelated to whether the sample is representative of the population of the United States.",
hasFigure: false,
},
];

315
src/data/math/index.ts Normal file
View File

@ -0,0 +1,315 @@
import { type TopicRegistry } from "../../types/lesson";
import {
LINEAR_EQ_ONE_VAR_EASY,
LINEAR_EQ_ONE_VAR_MEDIUM,
LINEAR_EQ_ONE_VAR_HARD,
} from "./linear-equations-one-var";
import {
LINEAR_EQ_TWO_VAR_EASY,
LINEAR_EQ_TWO_VAR_MEDIUM,
LINEAR_EQ_TWO_VAR_HARD,
} from "./linear-equations-two-var";
import {
LINEAR_FUNC_EASY,
LINEAR_FUNC_MEDIUM,
LINEAR_FUNC_HARD,
} from "./linear-functions";
import {
LINEAR_INEQ_EASY,
LINEAR_INEQ_MEDIUM,
LINEAR_INEQ_HARD,
} from "./linear-inequalities";
import {
SYSTEMS_EASY,
SYSTEMS_MEDIUM,
SYSTEMS_HARD,
} from "./systems-linear-equations";
import {
NONLINEAR_EQ_EASY,
NONLINEAR_EQ_MEDIUM,
NONLINEAR_EQ_HARD,
} from "./nonlinear-equations";
import {
NONLINEAR_FUNC_EASY,
NONLINEAR_FUNC_MEDIUM,
NONLINEAR_FUNC_HARD,
} from "./nonlinear-functions";
import {
EQUIV_EXPR_EASY,
EQUIV_EXPR_MEDIUM,
EQUIV_EXPR_HARD,
} from "./equivalent-expressions";
import { CIRCLES_EASY, CIRCLES_MEDIUM, CIRCLES_HARD } from "./circles";
import {
RIGHT_TRI_TRIG_EASY,
RIGHT_TRI_TRIG_MEDIUM,
RIGHT_TRI_TRIG_HARD,
} from "./right-triangles-trig";
import {
LINES_ANGLES_EASY,
LINES_ANGLES_MEDIUM,
LINES_ANGLES_HARD,
} from "./lines-angles-triangles";
import { AREA_VOL_EASY, AREA_VOL_MEDIUM, AREA_VOL_HARD } from "./area-volume";
import {
RATIOS_EASY,
RATIOS_MEDIUM,
RATIOS_HARD,
} from "./ratios-rates-proportions";
import {
PERCENTAGES_EASY,
PERCENTAGES_MEDIUM,
PERCENTAGES_HARD,
} from "./percentages";
import {
ONE_VAR_DATA_EASY,
ONE_VAR_DATA_MEDIUM,
ONE_VAR_DATA_HARD,
} from "./one-variable-data";
import {
TWO_VAR_DATA_EASY,
TWO_VAR_DATA_MEDIUM,
TWO_VAR_DATA_HARD,
} from "./two-variable-data";
import {
PROBABILITY_EASY,
PROBABILITY_MEDIUM,
PROBABILITY_HARD,
} from "./probability";
import {
EVAL_STATS_EASY,
EVAL_STATS_MEDIUM,
EVAL_STATS_HARD,
} from "./evaluating-statistical-claims";
import {
SAMPLE_STATS_EASY,
SAMPLE_STATS_MEDIUM,
SAMPLE_STATS_HARD,
} from "./sample-statistics-moe";
export const MATH_TOPICS: TopicRegistry = {
"linear-equations-one-var": {
id: "linear-equations-one-var",
name: "Linear Equations in One Variable",
section: "math",
category: "Algebra",
color: "blue",
questions: {
easy: LINEAR_EQ_ONE_VAR_EASY,
medium: LINEAR_EQ_ONE_VAR_MEDIUM,
hard: LINEAR_EQ_ONE_VAR_HARD,
},
},
"linear-equations-two-var": {
id: "linear-equations-two-var",
name: "Linear Equations in Two Variables",
section: "math",
category: "Algebra",
color: "blue",
questions: {
easy: LINEAR_EQ_TWO_VAR_EASY,
medium: LINEAR_EQ_TWO_VAR_MEDIUM,
hard: LINEAR_EQ_TWO_VAR_HARD,
},
},
"linear-functions": {
id: "linear-functions",
name: "Linear Functions",
section: "math",
category: "Algebra",
color: "blue",
questions: {
easy: LINEAR_FUNC_EASY,
medium: LINEAR_FUNC_MEDIUM,
hard: LINEAR_FUNC_HARD,
},
},
"linear-inequalities": {
id: "linear-inequalities",
name: "Linear Inequalities",
section: "math",
category: "Algebra",
color: "blue",
questions: {
easy: LINEAR_INEQ_EASY,
medium: LINEAR_INEQ_MEDIUM,
hard: LINEAR_INEQ_HARD,
},
},
"systems-linear-equations": {
id: "systems-linear-equations",
name: "Systems of Linear Equations",
section: "math",
category: "Algebra",
color: "blue",
questions: {
easy: SYSTEMS_EASY,
medium: SYSTEMS_MEDIUM,
hard: SYSTEMS_HARD,
},
},
"nonlinear-equations": {
id: "nonlinear-equations",
name: "Nonlinear Equations & Systems",
section: "math",
category: "Advanced Math",
color: "violet",
questions: {
easy: NONLINEAR_EQ_EASY,
medium: NONLINEAR_EQ_MEDIUM,
hard: NONLINEAR_EQ_HARD,
},
},
"nonlinear-functions": {
id: "nonlinear-functions",
name: "Nonlinear Functions",
section: "math",
category: "Advanced Math",
color: "violet",
questions: {
easy: NONLINEAR_FUNC_EASY,
medium: NONLINEAR_FUNC_MEDIUM,
hard: NONLINEAR_FUNC_HARD,
},
},
"equivalent-expressions": {
id: "equivalent-expressions",
name: "Equivalent Expressions",
section: "math",
category: "Advanced Math",
color: "violet",
questions: {
easy: EQUIV_EXPR_EASY,
medium: EQUIV_EXPR_MEDIUM,
hard: EQUIV_EXPR_HARD,
},
},
circles: {
id: "circles",
name: "Circles",
section: "math",
category: "Geometry & Trigonometry",
color: "emerald",
questions: {
easy: CIRCLES_EASY,
medium: CIRCLES_MEDIUM,
hard: CIRCLES_HARD,
},
},
"right-triangles-trig": {
id: "right-triangles-trig",
name: "Right Triangles & Trigonometry",
section: "math",
category: "Geometry & Trigonometry",
color: "emerald",
questions: {
easy: RIGHT_TRI_TRIG_EASY,
medium: RIGHT_TRI_TRIG_MEDIUM,
hard: RIGHT_TRI_TRIG_HARD,
},
},
"lines-angles-triangles": {
id: "lines-angles-triangles",
name: "Lines, Angles & Triangles",
section: "math",
category: "Geometry & Trigonometry",
color: "emerald",
questions: {
easy: LINES_ANGLES_EASY,
medium: LINES_ANGLES_MEDIUM,
hard: LINES_ANGLES_HARD,
},
},
"area-volume": {
id: "area-volume",
name: "Area & Volume",
section: "math",
category: "Geometry & Trigonometry",
color: "emerald",
questions: {
easy: AREA_VOL_EASY,
medium: AREA_VOL_MEDIUM,
hard: AREA_VOL_HARD,
},
},
"ratios-rates-proportions": {
id: "ratios-rates-proportions",
name: "Ratios, Rates & Proportions",
section: "math",
category: "Data Analysis",
color: "amber",
questions: { easy: RATIOS_EASY, medium: RATIOS_MEDIUM, hard: RATIOS_HARD },
},
percentages: {
id: "percentages",
name: "Percentages",
section: "math",
category: "Data Analysis",
color: "amber",
questions: {
easy: PERCENTAGES_EASY,
medium: PERCENTAGES_MEDIUM,
hard: PERCENTAGES_HARD,
},
},
"one-variable-data": {
id: "one-variable-data",
name: "One-Variable Data",
section: "math",
category: "Data Analysis",
color: "amber",
questions: {
easy: ONE_VAR_DATA_EASY,
medium: ONE_VAR_DATA_MEDIUM,
hard: ONE_VAR_DATA_HARD,
},
},
"two-variable-data": {
id: "two-variable-data",
name: "Two-Variable Data",
section: "math",
category: "Data Analysis",
color: "amber",
questions: {
easy: TWO_VAR_DATA_EASY,
medium: TWO_VAR_DATA_MEDIUM,
hard: TWO_VAR_DATA_HARD,
},
},
probability: {
id: "probability",
name: "Probability",
section: "math",
category: "Data Analysis",
color: "amber",
questions: {
easy: PROBABILITY_EASY,
medium: PROBABILITY_MEDIUM,
hard: PROBABILITY_HARD,
},
},
"evaluating-statistical-claims": {
id: "evaluating-statistical-claims",
name: "Evaluating Statistical Claims",
section: "math",
category: "Data Analysis",
color: "amber",
questions: {
easy: EVAL_STATS_EASY,
medium: EVAL_STATS_MEDIUM,
hard: EVAL_STATS_HARD,
},
},
"sample-statistics-moe": {
id: "sample-statistics-moe",
name: "Sample Statistics & Margin of Error",
section: "math",
category: "Data Analysis",
color: "amber",
questions: {
easy: SAMPLE_STATS_EASY,
medium: SAMPLE_STATS_MEDIUM,
hard: SAMPLE_STATS_HARD,
},
},
};

View File

@ -0,0 +1,988 @@
import { type PracticeQuestion } from "../../types/lesson";
export const LINEAR_EQ_ONE_VAR_EASY: PracticeQuestion[] = [
{
id: "097e10f5",
type: "mcq",
questionHtml:
"What value of <strong>p</strong> satisfies the equation <strong>5 p + 180 = 250</strong>?",
choices: [
{ label: "A", text: "<strong>14</strong>" },
{ label: "B", text: "<strong>65</strong>" },
{ label: "C", text: "<strong>86</strong>" },
{ label: "D", text: "<strong>250</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Subtracting <strong>180</strong> from both sides of the given equation yields <strong>5 p = 70</strong>. Dividing both sides of this equation by <strong>5</strong> yields <strong>p = 14</strong>. Therefore, the value of <strong>p</strong> that satisfies the equation <strong>5 p + 180 = 250</strong> is <strong>14</strong>.<br>Choice B is incorrect. This value of <strong>p</strong> satisfies the equation <strong>5 p + 180 = 505</strong>.<br>Choice C is incorrect. This value of <strong>p</strong> satisfies the equation <strong>5 p + 180 = 610</strong>.<br>Choice D is incorrect. This value of <strong>p</strong> satisfies the equation <strong>5 p + 180 = 1, 430</strong>.",
hasFigure: false,
},
{
id: "0d685865",
type: "mcq",
questionHtml:
"If <strong>x = 7</strong>, what is the value of <strong>x + 20</strong>?",
choices: [
{ label: "A", text: "<strong>13</strong>" },
{ label: "B", text: "<strong>20</strong>" },
{ label: "C", text: "<strong>27</strong>" },
{ label: "D", text: "<strong>34</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that <strong>x = 7</strong>. Substituting <strong>7</strong> for <strong>x</strong> into the given expression <strong>x + 20</strong> yields <strong>7 + 20</strong>, which is equivalent to <strong>27</strong>.<br>Choice A is incorrect. This is the value of <strong>x + 6</strong>.<br>Choice B is incorrect. This is the value of <strong>x + 13</strong>.<br>Choice D is incorrect. This is the value of <strong>x + 27</strong>.",
hasFigure: false,
},
{
id: "12255364",
type: "mcq",
questionHtml:
"A gym charges its members a onetime <strong>dollar sign 36</strong> enrollment fee and a membership fee of <strong>dollar sign 19</strong> per month. If there are no charges other than the enrollment fee and the membership fee, after how many months will a member have been charged a total of <strong>dollar sign 188</strong> at the gym?",
choices: [
{ label: "A", text: "<strong>4</strong>" },
{ label: "B", text: "<strong>5</strong>" },
{ label: "C", text: "<strong>8</strong>" },
{ label: "D", text: "<strong>10</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that a gym charges its members a onetime <strong>dollar sign 36</strong> enrollment fee and a membership fee of <strong>dollar sign 19</strong> per month. Let <strong>x</strong> represent the number of months at the gym after which a member will have been charged a total of <strong>dollar sign 188</strong>. If there are no charges other than the enrollment fee and the membership fee, the equation <strong>36 + 19 x = 188</strong> can be used to represent this situation. Subtracting <strong>36</strong> from both sides of this equation yields <strong>19 x = 152</strong>. Dividing both sides of this equation by <strong>19</strong> yields <strong>x = 8</strong>. Therefore, a member will have been charged a total of <strong>dollar sign 188</strong> after <strong>8</strong> months at the gym.<br>Choice A is incorrect. A member will have been charged a total of <strong>dollar sign (36 + 19 · 4)</strong>, or <strong>dollar sign 112</strong>, after <strong>4</strong> months at the gym.<br>Choice B is incorrect. A member will have been charged a total of <strong>dollar sign (36 + 19 · 5)</strong>, or <strong>dollar sign 131</strong>, after <strong>5</strong> months at the gym.<br>Choice D is incorrect. A member will have been charged a total of <strong>dollar sign (36 + 19 · 10)</strong>, or <strong>dollar sign 226</strong>, after <strong>10</strong> months at the gym.",
hasFigure: false,
},
{
id: "2f0a43b2",
type: "spr",
questionHtml:
"If <strong>(x) / (8) = 5</strong>, what is the value of <strong>(8) / (x)</strong>?",
choices: [],
correctAnswer: ".2, 1/5",
explanation:
"The correct answer is <strong>one fifth</strong>. Since the number <strong>5</strong> can also be written as <strong>five oneths</strong>, the given equation can also be written as <strong>(x) / (8) = five oneths</strong>. This equation is equivalent to <strong>(8) / (x) = one fifth</strong>. Therefore, the value of <strong>(8) / (x)</strong> is <strong>one fifth</strong>. Note that 1/5 and .2 are examples of ways to enter a correct answer.<br>Alternate approach: Multiplying both sides of the equation <strong>(x) / (8) = 5</strong> by <strong>8</strong> yields <strong>x = 40</strong>. Substituting <strong>40</strong> for <strong>x</strong> into the expression <strong>(8) / (x)</strong> yields <strong>eight fortieths</strong>, or <strong>one fifth</strong>.",
hasFigure: false,
},
{
id: "349a5bc1",
type: "spr",
questionHtml:
"<strong>4 x + 5 = 165</strong><br>What is the solution to the given equation?",
choices: [],
correctAnswer: "40",
explanation:
"The correct answer is <strong>40</strong>. Subtracting <strong>5</strong> from both sides of the given equation yields <strong>4 x = 160</strong>. Dividing both sides of this equation by <strong>4</strong> yields <strong>x = 40</strong>. Therefore, the solution to the given equation is <strong>40</strong>.",
hasFigure: false,
},
{
id: "3c4ce699",
type: "spr",
questionHtml:
"If <strong>6 + x = 9</strong>, what is the value of <strong>18 + 3 x</strong>?",
choices: [],
correctAnswer: "27",
explanation:
"The correct answer is <strong>27</strong>. Multiplying both sides of the given equation by <strong>3</strong> yields <strong>3 (6 + x) = 3 (9)</strong>, or <strong>18 + 3 x = 27</strong>. Therefore, the value of <strong>18 + 3 x</strong> is <strong>27</strong>.",
hasFigure: false,
},
{
id: "3d04de9c",
type: "mcq",
questionHtml:
"A principal used a total of <strong>25</strong> flags that were either blue or yellow for field day. The principal used <strong>20</strong> blue flags. How many yellow flags were used?",
choices: [
{ label: "A", text: "<strong>5</strong>" },
{ label: "B", text: "<strong>20</strong>" },
{ label: "C", text: "<strong>25</strong>" },
{ label: "D", text: "<strong>30</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. It's given that a principal used a total of <strong>25</strong> blue flags and yellow flags. It's also given that of the <strong>25</strong> flags used, <strong>20</strong> flags were blue. Subtracting the number of blue flags used from the total number of flags used results in the number of yellow flags used. It follows that the number of yellow flags used is <strong>25 20</strong>, or <strong>5</strong>. <br>Choice B is incorrect. This is the number of blue flags used.<br>Choice C is incorrect. This is the total number of flags used.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "46f68129",
type: "mcq",
questionHtml:
"A librarian has 43 books to distribute to a group of children. If he gives each child 2 books, he will have 7 books left over. How many children are in the group?",
choices: [
{ label: "A", text: "15" },
{ label: "B", text: "18" },
{ label: "C", text: "25" },
{ label: "D", text: "29" },
],
correctAnswer: "",
explanation:
"Choice B is correct. Subtracting the number of books left over from the total number of books results in <strong>43 7 = 36</strong>, which is the number of books distributed. Dividing the number of books distributed by the number of books given to each child results in <strong>the fraction 36 over 2 = 18</strong>.Choice A is incorrect and results from dividing the total number of books by the number of books given to each child, <strong>the fraction 43 over 2, is ≈ 22</strong>, then subtracting the number of books left over from the result, <strong>22 7 = 15</strong>. Choice C is incorrect and results from adding the number of books left over to the total number of books, <strong>43 + 7 = 50</strong>, then dividing the result by the number of books given to each child, <strong>the fraction 50 over 2 = 25</strong>. Choice D is incorrect and results from dividing the total number of books by the number of books given to each child, <strong>the fraction 43 over 2, is ≈ 22</strong>, then adding the number of books left over, <strong>22 + 7 = 29</strong>.",
hasFigure: false,
},
{
id: "4de87c9a",
type: "mcq",
questionHtml:
"<strong>3</strong> more than <strong>8</strong> times a number <strong>x</strong> is equal to <strong>83</strong>. Which equation represents this situation?",
choices: [
{ label: "A", text: "<strong>(3) (8) x = 83</strong>" },
{ label: "B", text: "<strong>8 x = 83 + 3</strong>" },
{ label: "C", text: "<strong>3 x + 8 = 83</strong>" },
{ label: "D", text: "<strong>8 x + 3 = 83</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The given phrase “<strong>8</strong> times a number <strong>x</strong>” can be represented by the expression <strong>8 x</strong>. The given phrase “<strong>3</strong> more than” indicates an increase of <strong>3</strong> to a quantity. Therefore “<strong>3</strong> more than <strong>8</strong> times a number <strong>x</strong>” can be represented by the expression <strong>8 x + 3</strong>. Since its given that <strong>3</strong> more than <strong>8</strong> times a number <strong>x</strong> is equal to <strong>83</strong>, it follows that <strong>8 x + 3</strong> is equal to <strong>83</strong>, or <strong>8 x + 3 = 83</strong>. Therefore, the equation that represents this situation is <strong>8 x + 3 = 83</strong>.<br>Choice A is incorrect. This equation represents <strong>3</strong> times the quantity <strong>8</strong> times a number <strong>x</strong> is equal to <strong>83</strong>. <br>Choice B is incorrect. This equation represents <strong>8</strong> times a number <strong>x</strong> is equal to <strong>3</strong> more than <strong>83</strong>.<br>Choice C is incorrect. This equation represents <strong>8</strong> more than <strong>3</strong> times a number <strong>x</strong> is equal to <strong>83</strong>.",
hasFigure: false,
},
{
id: "4e77195b",
type: "spr",
questionHtml:
"If <strong>2 + x = 60</strong>, what is the value of <strong>16 + 8 x</strong>?",
choices: [],
correctAnswer: "480",
explanation:
"The correct answer is <strong>480</strong>. Multiplying both sides of the given equation by <strong>8</strong> yields <strong>8 (2 + x) = 8 (60)</strong>, or <strong>16 + 8 x = 480</strong>. Therefore, if <strong>2 + x = 60</strong>, the value of <strong>16 + 8 x</strong> is <strong>480</strong>.",
hasFigure: false,
},
{
id: "4f7981a0",
type: "spr",
questionHtml:
"If <strong>3 x + 2 = 8</strong>, what is the value of <strong>9 x + 6</strong> ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 24. Multiplying both sides of the given equation by 3 yields <strong>3 · (3 x + 2, ) = 24</strong>. Using the distributive property to rewrite the left-hand side of this equation yields <strong>9 x + 6 = 24</strong>.",
hasFigure: false,
},
{
id: "550b352c",
type: "mcq",
questionHtml: "How many solutions exist to the equation shown above?",
choices: [
{ label: "A", text: "None" },
{ label: "B", text: "Exactly 1" },
{ label: "C", text: "Exactly 3" },
{ label: "D", text: "Infinitely many" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Subtracting 4 from each side of the given equation yields <strong>6 = 2 x</strong>, or <strong>x = 3</strong>, so the equation has a unique solution of <strong>x = 3</strong>.Choice A is incorrect. Since 3 is a value of x that satisfies the given equation, the equation has at least 1 solution. Choice C is incorrect. Linear equations can have 0, 1, or infinitely many solutions; no linear equation has exactly 3 solutions. Choice D is incorrect. If a linear equation has infinitely many solutions, it can be reduced to <strong>0 = 0</strong>. This equation reduces to <strong>x = 3</strong>, so there is only 1 solution.",
hasFigure: false,
},
{
id: "5c94e6fa",
type: "spr",
questionHtml:
"<strong>3 x + 21 = 3 x + k</strong><br>In the given equation, <strong>k</strong> is a constant. The equation has infinitely many solutions. What is the value of <strong>k</strong>?",
choices: [],
correctAnswer: "21",
explanation:
"The correct answer is <strong>21</strong>. It's given that the equation <strong>3 x + 21 = 3 x + k</strong> has infinitely many solutions. If an equation in one variable has infinitely many solutions, then the equation is true for any value of the variable. Subtracting <strong>3 x</strong> from both sides of the given equation yields <strong>k = 21</strong>. Since this equation must be true for any value of <strong>x</strong>, the value of <strong>k</strong> is <strong>21</strong>.",
hasFigure: false,
},
{
id: "60f71697",
type: "mcq",
questionHtml:
"<strong>8 x = 88</strong><br>What value of <strong>x</strong> is the solution to the given equation?",
choices: [
{ label: "A", text: "<strong>11</strong>" },
{ label: "B", text: "<strong>80</strong>" },
{ label: "C", text: "<strong>96</strong>" },
{ label: "D", text: "<strong>704</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Dividing both sides of the given equation by <strong>8</strong> yields <strong>x = 11</strong>. Therefore, <strong>11</strong> is the solution to the given equation.<br>Choice B is incorrect. This is the solution to the equation <strong>x + 8 = 88</strong>.<br>Choice C is incorrect. This is the solution to the equation <strong>x 8 = 88</strong>.<br>Choice D is incorrect. This is the solution to the equation <strong>(x) / (8) = 88</strong>.",
hasFigure: false,
},
{
id: "6105234d",
type: "mcq",
questionHtml:
"John paid a total of <strong>dollar sign 165</strong> for a microscope by making a down payment of <strong>dollar sign 37</strong> plus <strong>p</strong> monthly payments of <strong>dollar sign 16</strong> each. Which of the following equations represents this situation?",
choices: [
{ label: "A", text: "<strong>16 p 37 = 165</strong>" },
{ label: "B", text: "<strong>37 p 16 = 165</strong>" },
{ label: "C", text: "<strong>16 p + 37 = 165</strong>" },
{ label: "D", text: "<strong>37 p + 16 = 165</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that John made a <strong>dollar sign 16</strong> payment each month for <strong>p</strong> months. The total amount of these payments can be represented by the expression <strong>16 p</strong>. The down payment can be added to that amount to find the total amount John paid, yielding the expression <strong>16 p + 37</strong>. Its given that John paid a total of <strong>dollar sign 165</strong>. Therefore, the expression for the total amount John paid can be set equal to that amount, yielding the equation <strong>16 p + 37 = 165</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "6ac23de7",
type: "mcq",
questionHtml:
"<strong>the fraction 4 x over 5 = 20</strong>In the equation above, what is the value of x ?",
choices: [
{ label: "A", text: "25" },
{ label: "B", text: "24" },
{ label: "C", text: "16" },
{ label: "D", text: "15" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Multiplying both sides of the equation by 5 results in <strong>4 x = 100</strong>. Dividing both sides of the resulting equation by 4 results in <strong>x = 25</strong>.Choice B is incorrect and may result from adding 20 and 4. Choice C is incorrect and may result from dividing 20 by 5 and then multiplying the result by 4. Choice D is incorrect and may result from subtracting 5 from 20.",
hasFigure: false,
},
{
id: "6fa593f1",
type: "mcq",
questionHtml:
"If <strong>x = 40</strong>, what is the value of <strong>x + 6</strong>?",
choices: [
{ label: "A", text: "<strong>34</strong>" },
{ label: "B", text: "<strong>40</strong>" },
{ label: "C", text: "<strong>46</strong>" },
{ label: "D", text: "<strong>64</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. It's given that <strong>x = 40</strong>. Adding <strong>6</strong> to both sides of this equation yields <strong>x + 6 = 40 + 6</strong>, or <strong>x + 6 = 46</strong>. Therefore, the value of <strong>x + 6</strong> is <strong>46</strong>.<br>Choice A is incorrect. This is the value of <strong>x 6</strong>, not <strong>x + 6</strong>.<br>Choice B is incorrect. This is the value of <strong>x</strong>, not <strong>x + 6</strong>.<br>Choice D is incorrect. This is the value of <strong>x + 24</strong>, not <strong>x + 6</strong>.",
hasFigure: false,
},
{
id: "70774aa4",
type: "mcq",
questionHtml:
"If <strong>5 x = 20</strong>, what is the value of <strong>15 x</strong>?",
choices: [
{ label: "A", text: "<strong>7</strong>" },
{ label: "B", text: "<strong>12</strong>" },
{ label: "C", text: "<strong>23</strong>" },
{ label: "D", text: "<strong>60</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Its given that <strong>5 x = 20</strong>. Multiplying both sides of this equation by <strong>3</strong> yields <strong>15 x = 60</strong>. Therefore, the value of <strong>15 x</strong> is <strong>60</strong>.<br>Choice A is incorrect and may result from conceptual errors.<br>Choice B is incorrect and may result from conceptual errors.<br>Choice C is incorrect and may result from conceptual errors.",
hasFigure: false,
},
{
id: "7392dfc1",
type: "mcq",
questionHtml:
"Which of the following is equivalent to <strong>4 x + 6 = 12</strong> ?",
choices: [
{ label: "A", text: "<strong>2 x + 4 = 6</strong>" },
{ label: "B", text: "<strong>x + 3 = 3</strong>" },
{ label: "C", text: "<strong>3 x + 2 = 4</strong>" },
{ label: "D", text: "<strong>2 x + 3 = 6</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Dividing each side of the original equation by [] yields <strong>the fraction with numerator 4 x + 6, and denominator 2 = twelve halves</strong>, which simplifies to <strong>2 x + 3 = 6</strong>.Choice A is incorrect. Dividing each side of the original equation by [] gives <strong>2 x + 3 = 6</strong>, which is not equivalent to <strong>2 x + 4 = 6</strong>. Choice B is incorrect. Dividing each side of the original equation by [] gives <strong>x + three halves = 3</strong>, which is not equivalent to <strong>x + 3 = 3</strong>. Choice C is incorrect. Dividing each side of the original equation by [] gives <strong>four thirds x + 2 = 4</strong>, which is not equivalent to <strong>3 x + 2 = 4</strong>.",
hasFigure: false,
},
{
id: "7a987ae4",
type: "mcq",
questionHtml:
"If <strong>2 n over 5 = 10</strong>, what is the value of <strong>2 n 1</strong> ?",
choices: [
{ label: "A", text: "24" },
{ label: "B", text: "49" },
{ label: "C", text: "50" },
{ label: "D", text: "99" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Multiplying both sides of the given equation by 5 yields <strong>2 n = 50</strong>. Substituting 50 for <strong>2 n</strong> in the expression <strong>2 n 1</strong> yields <strong>50 1 = 49</strong>.Alternate approach: Dividing both sides of <strong>2 n = 50</strong> by 2 yields <strong>n = 25</strong>. Evaluating the expression <strong>2 n 1</strong> for <strong>n = 25</strong> yields <strong>2 · 25 1 = 49</strong>.<br>Choice A is incorrect and may result from finding the value of <strong>n 1</strong> instead of <strong>2 n 1</strong>. Choice C is incorrect and may result from finding the value of <strong>2 n</strong> instead of <strong>2 n 1</strong>. Choice D is incorrect and may result from finding the value of <strong>4 n 1</strong> instead of <strong>2 n 1</strong>.",
hasFigure: false,
},
{
id: "8339793c",
type: "spr",
questionHtml:
"Nasir bought <strong>9</strong> storage bins that were each the same price. He used a coupon for <strong>dollar sign 63</strong> off the entire purchase. The cost for the entire purchase after using the coupon was <strong>dollar sign 27</strong>. What was the original price, in dollars, for <strong>1</strong> storage bin?",
choices: [],
correctAnswer: "10",
explanation:
"The correct answer is <strong>10</strong>. Its given that the cost for the entire purchase was <strong>dollar sign 27</strong> after a coupon was used for <strong>dollar sign 63</strong> off the entire purchase. Adding the amount of the coupon to the purchase price yields <strong>27 + 63 = 90</strong>. Thus, the cost for the entire purchase before using the coupon was <strong>dollar sign 90</strong>. Its given that Nasir bought <strong>9</strong> storage bins. The original price for <strong>1</strong> storage bin can be found by dividing the total cost by <strong>9</strong>. Therefore, the original price, in dollars, for <strong>1</strong> storage bin is <strong>(90) / (9)</strong>, or <strong>10</strong>.",
hasFigure: false,
},
{
id: "87071893",
type: "spr",
questionHtml:
"<strong>x + 40 = 95</strong><br>What value of <strong>x</strong> is the solution to the given equation?",
choices: [],
correctAnswer: "55",
explanation:
"The correct answer is <strong>55</strong>. Subtracting <strong>40</strong> from both sides of the given equation yields <strong>x = 55</strong>. Therefore, the value of <strong>x</strong> is <strong>55</strong>.",
hasFigure: false,
},
{
id: "93954cfa",
type: "mcq",
questionHtml:
"One pound of grapes costs $2. At this rate, how many dollars will c pounds of grapes cost?",
choices: [
{ label: "A", text: "<strong>2 c</strong>" },
{ label: "B", text: "<strong>2 + c</strong>" },
{ label: "C", text: "<strong>the fraction 2 over c</strong>" },
{ label: "D", text: "<strong>the fraction c over 2</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. If one pound of grapes costs $2, two pounds of grapes will cost 2 times $2, three pounds of grapes will cost 3 times $2, and so on. Therefore, c pounds of grapes will cost c times $2, which is 2c dollars.Choice B is incorrect and may result from incorrectly adding instead of multiplying. Choice C is incorrect and may result from assuming that c pounds cost $2, and then finding the cost per pound. Choice D is incorrect and could result from incorrectly assuming that 2 pounds cost $c, and then finding the cost per pound.",
hasFigure: false,
},
{
id: "997bec28",
type: "spr",
questionHtml:
"The perimeter of an isosceles triangle is <strong>83</strong> inches. Each of the two congruent sides of the triangle has a length of <strong>24</strong> inches. What is the length, in inches, of the third side?",
choices: [],
correctAnswer: "35",
explanation:
"The correct answer is <strong>35</strong>. Its given that the perimeter of an isosceles triangle is <strong>83</strong> inches and that each of the two congruent sides has a length of <strong>24</strong> inches. The perimeter of a triangle is the sum of the lengths of its three sides. The equation <strong>24 + 24 + x = 83</strong> can be used to represent this situation, where <strong>x</strong> is the length, in inches, of the third side. Combining like terms on the left-hand side of this equation yields <strong>48 + x = 83</strong>. Subtracting <strong>48</strong> from both sides of this equation yields <strong>x = 35</strong>. Therefore, the length, in inches, of the third side is <strong>35</strong>.",
hasFigure: false,
},
{
id: "9ff10b3b",
type: "mcq",
questionHtml:
"If <strong>one half x one sixth x = 1</strong>, what is the value of x ?",
choices: [
{ label: "A", text: "<strong>4</strong>" },
{ label: "B", text: "<strong>one third</strong>" },
{ label: "C", text: "<strong>3</strong>" },
{ label: "D", text: "<strong>6</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. To make it easier to add like terms on the left-hand side of the given equation, both sides of the equation can be multiplied by 6, which is the lowest common denominator of <strong>one half</strong> and <strong>one sixth</strong>. This yields <strong>3 x x = 6</strong>, which can be rewritten as <strong>2 x = 6</strong>. Dividing both sides of this equation by 2 yields <strong>x = 3</strong>.Choice A is incorrect and may result from subtracting the denominators instead of numerators with common denominators to get <strong>one fourth x</strong>, rather than <strong>one third x</strong>, on the left-hand side of the equation. Choice B is incorrect and may result from rewriting the given equation as <strong>one half x = one sixth</strong> instead of <strong>2 x = 6</strong>. Choice D is incorrect and may result from conceptual or computational errors.",
hasFigure: false,
},
{
id: "a9c04a21",
type: "mcq",
questionHtml:
"What is the solution to the equation <strong>2 x + 3 = 7</strong>?",
choices: [
{ label: "A", text: "1" },
{ label: "B", text: "1.5" },
{ label: "C", text: "2" },
{ label: "D", text: "4" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Subtracting 3 from both sides of the given equation yields <strong>2 x = 4</strong>. Dividing both sides by 2 results in <strong>x = 2</strong>.Choices A and B are incorrect and may result from computational errors. Choice D is incorrect. This is the value of <strong>2 x</strong>.",
hasFigure: false,
},
{
id: "b4553284",
type: "spr",
questionHtml:
"If <strong>2 x = 12</strong>, what is the value of <strong>9 x</strong>?",
choices: [],
correctAnswer: "54",
explanation:
"The correct answer is <strong>54</strong>. Dividing both sides of the given equation by <strong>2</strong> yields <strong>x = 6</strong>. Multiplying both sides of this equation by <strong>9</strong> yields <strong>9 x = 54</strong>. Thus, the value of <strong>9 x</strong> is <strong>54</strong>.",
hasFigure: false,
},
{
id: "b82a943c",
type: "mcq",
questionHtml:
"If <strong>7 x = 28</strong>, what is the value of <strong>8 x</strong>?",
choices: [
{ label: "A", text: "<strong>21</strong>" },
{ label: "B", text: "<strong>32</strong>" },
{ label: "C", text: "<strong>168</strong>" },
{ label: "D", text: "<strong>224</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Dividing both sides of the given equation <strong>7 x = 28</strong> by <strong>7</strong> yields <strong>x = 4</strong>. Substituting <strong>4</strong> for <strong>x</strong> in the expression <strong>8 x</strong> yields <strong>8 (4)</strong>, which is equivalent to <strong>32</strong>.<br>Choice A is incorrect. This is the value of <strong>(21) / (4) x</strong>.<br>Choice C is incorrect. This is the value of <strong>42 x</strong>.<br>Choice D is incorrect. This is the value of <strong>56 x</strong>.",
hasFigure: false,
},
{
id: "c3989ef8",
type: "mcq",
questionHtml:
"Henry receives a <strong>dollar sign 60.00</strong> gift card to pay for movies online. He uses his gift card to buy <strong>3</strong> movies for <strong>dollar sign 7.50</strong> each. If he spends the rest of his gift card balance on renting movies for <strong>dollar sign 1.50</strong> each, how many movies can Henry rent?",
choices: [
{ label: "A", text: "<strong>10</strong>" },
{ label: "B", text: "<strong>25</strong>" },
{ label: "C", text: "<strong>35</strong>" },
{ label: "D", text: "<strong>40</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. It's given that Henry uses his <strong>dollar sign 60.00</strong> gift card to buy <strong>3</strong> movies for <strong>dollar sign 7.50</strong> each. Therefore, Henry spends <strong>3 (dollar sign 7.50)</strong>, or <strong>dollar sign 22.50</strong>, of his <strong>dollar sign 60.00</strong> gift card to buy <strong>3</strong> movies. After buying <strong>3</strong> movies with his <strong>dollar sign 60.00</strong> gift card, Henry has a gift card balance of <strong>dollar sign 60.00 dollar sign 22.50</strong>, or <strong>dollar sign 37.50</strong>. It's also given that Henry spends the rest of his gift card balance on renting movies for <strong>dollar sign 1.50</strong> each. Therefore, Henry can rent <strong>(dollar sign 37.50) / (dollar sign 1.50)</strong>, or <strong>25</strong>, movies.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "c841e8e8",
type: "mcq",
questionHtml:
"<strong>k + 12 = 336</strong><br>What is the solution to the given equation?",
choices: [
{ label: "A", text: "<strong>28</strong>" },
{ label: "B", text: "<strong>324</strong>" },
{ label: "C", text: "<strong>348</strong>" },
{ label: "D", text: "<strong>4, 032</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Subtracting <strong>12</strong> from both sides of the given equation yields <strong>k = 324</strong>. Therefore, the solution to the given equation is <strong>324</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "d9d83c02",
type: "mcq",
questionHtml:
"For what value of w does <strong>w 10 = 2 · (w + 5, )</strong> ?",
choices: [
{ label: "A", text: "[]" },
{ label: "B", text: "<strong>0</strong>" },
{ label: "C", text: "<strong>15</strong>" },
{ label: "D", text: "<strong>20</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. To solve the equation, use the distributive property to multiply on the right-hand side of the equation which gives w 10 = 2w + 10. Subtract w from both sides of the equation, which gives 10 = w + 10. Finally, subtract 10 from both sides of the equation, which gives 20 = w.Choices A and B are incorrect and may result from making sign errors. Choice C is incorrect and may result from incompletely distributing the 2 in the expression 2(w + 5).",
hasFigure: false,
},
{
id: "e53870b6",
type: "spr",
questionHtml:
"In the given equation, k is a constant. If the equation has infinitely many solutions, what is the value of k ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 5. Subtracting <strong>6 x</strong> from both sides of the given equation gives <strong>k = 5</strong>, so for any value of x, <strong>6 x + k = 6 x + 5</strong> if and only if <strong>k = 5</strong>. Therefore, if the given equation has infinitely many solutions, the value of k is 5.",
hasFigure: false,
},
{
id: "e7b6f0d1",
type: "mcq",
questionHtml:
"<strong>4 x + 6 = 18</strong><br>Which equation has the same solution as the given equation?",
choices: [
{ label: "A", text: "<strong>4 x = 108</strong>" },
{ label: "B", text: "<strong>4 x = 24</strong>" },
{ label: "C", text: "<strong>4 x = 12</strong>" },
{ label: "D", text: "<strong>4 x = 3</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Subtracting <strong>6</strong> from both sides of the given equation yields <strong>4 x = 12</strong>, which is the equation given in choice C. Since this equation is equivalent to the given equation, it has the same solution as the given equation.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "eac739b2",
type: "mcq",
questionHtml:
"If <strong>4 x + 2 = 12</strong>, what is the value of <strong>16 x + 8</strong>?",
choices: [
{ label: "A", text: "<strong>40</strong>" },
{ label: "B", text: "<strong>48</strong>" },
{ label: "C", text: "<strong>56</strong>" },
{ label: "D", text: "<strong>60</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Multiplying both sides of the given equation by <strong>4</strong> yields <strong>(4) (4 x + 2) = (4) (12)</strong>, or <strong>16 x + 8 = 48</strong>. Therefore, the value of <strong>16 x + 8</strong> is <strong>48</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "ed18c4f7",
type: "mcq",
questionHtml:
"Cathy has n CDs. Gerry has 3 more than twice the number of CDs that Cathy has. In terms of n, how many CDs does Gerry have?",
choices: [
{ label: "A", text: "<strong>3 n 2</strong>" },
{ label: "B", text: "<strong>3 n + 2</strong>" },
{ label: "C", text: "<strong>2 n 3</strong>" },
{ label: "D", text: "<strong>2 n + 3</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The term 2n represents twice the number of CDs that Cathy has, and adding 3 represents 3 more than that amount.Choices A and B are incorrect. The expression 3n represents three times the number of CDs that Cathy has. Choice C is incorrect. Subtracting 3 represents 3 fewer than twice the number of CDs that Cathy has.",
hasFigure: false,
},
{
id: "fbb0ea7f",
type: "mcq",
questionHtml:
"A rocket contained <strong>467, 000</strong> kilograms (kg) of propellant before launch. Exactly <strong>21</strong> seconds after launch, <strong>362, 105</strong> kg of this propellant remained. On average, approximately how much propellant, in kg, did the rocket burn each second after launch?",
choices: [
{ label: "A", text: "<strong>4, 995</strong>" },
{ label: "B", text: "<strong>17, 243</strong>" },
{ label: "C", text: "<strong>39, 481</strong>" },
{ label: "D", text: "<strong>104, 895</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that the rocket contained <strong>467, 000 kilograms (kg)</strong> of propellant before launch and had <strong>362, 105 kg</strong> remaining exactly <strong>21</strong> seconds after launch. Finding the difference between the amount, in <strong>kg</strong>, of propellant before launch and the remaining amount, in <strong>kg</strong>, of propellant after launch gives the amount, in <strong>kg</strong>, of propellant burned during the <strong>21</strong> seconds: <strong>467, 000 362, 105 = 104, 895</strong>. Dividing the amount of propellant burned by the number of seconds yields <strong>(104, 895) / (21) = 4, 995</strong>. Thus, an average of <strong>4, 995 kg</strong> of propellant burned each second after launch.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from finding the amount of propellant burned, rather than the amount of propellant burned each second.",
hasFigure: false,
},
];
export const LINEAR_EQ_ONE_VAR_MEDIUM: PracticeQuestion[] = [
{
id: "12ee1edc",
type: "mcq",
questionHtml:
"In the given equation, b is a constant. If the equation has no solution, what is the value of b ?",
choices: [
{ label: "A", text: "2" },
{ label: "B", text: "4" },
{ label: "C", text: "6" },
{ label: "D", text: "10" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. This equation has no solution when there is no value of x that produces a true statement. Solving the given equation for x by dividing both sides by <strong>(b 2, )</strong> gives <strong>x = the fraction with numerator 8, and denominator, (b 2, )</strong>. When <strong>(b 2, ) = 0</strong>, the right-hand side of this equation will be undefined, and the equation will have no solution. Therefore, when <strong>b = 2</strong>, there is no value of x that satisfies the given equation.Choices B, C, and D are incorrect. Substituting 4, 6, and 10 for b in the given equation yields exactly one solution, rather than no solution, for x. For example, substituting 4 for b in the given equation yields <strong>(4 2, ) · x = 8</strong>, or <strong>2 x = 8</strong>. Dividing both sides of <strong>2 x = 8</strong> by 2 yields <strong>x = 4</strong>. Similarly, if <strong>b = 6</strong> or <strong>b = 10</strong>, <strong>x = 2</strong> and <strong>x = 1</strong>, respectively.",
hasFigure: false,
},
{
id: "15daa8d6",
type: "spr",
questionHtml:
"<strong>2 x + 16 = a (x + 8)</strong><br>In the given equation, <strong>a</strong> is a constant. If the equation has infinitely many solutions, what is the value of <strong>a</strong>?",
choices: [],
correctAnswer: "2",
explanation:
"The correct answer is <strong>2</strong>. An equation with one variable, <strong>x</strong>, has infinitely many solutions only when both sides of the equation are equal for any defined value of <strong>x</strong>. It's given that <strong>2 x + 16 = a (x + 8)</strong>, where <strong>a</strong> is a constant. This equation can be rewritten as <strong>2 (x + 8) = a (x + 8)</strong>. If this equation has infinitely many solutions, then both sides of this equation are equal for any defined value of <strong>x</strong>. Both sides of this equation are equal for any defined value of <strong>x</strong> when <strong>2 = a</strong>. Therefore, if the equation has infinitely many solutions, the value of <strong>a</strong> is <strong>2</strong>.<br>Alternate approach: If the given equation, <strong>2 x + 16 = a (x + 8)</strong>, has infinitely many solutions, then both sides of this equation are equal for any value of <strong>x</strong>. If <strong>x = 0</strong>, then substituting <strong>0</strong> for <strong>x</strong> in <strong>2 x + 16 = a (x + 8)</strong> yields <strong>2 (0) + 16 = a (0 + 8)</strong>, or <strong>16 = 8 a</strong>. Dividing both sides of this equation by <strong>8</strong> yields <strong>2 = a</strong>.",
hasFigure: false,
},
{
id: "36ab4122",
type: "mcq",
questionHtml:
"Megans regular wage at her job is p dollars per hour for the first 8 hours of work in a day plus 1.5 times her regular hourly wage for work in excess of 8 hours that day. On a given day, Megan worked for 10 hours, and her total earnings for that day were $137.50. What is Megans regular hourly wage?",
choices: [
{ label: "A", text: "$11.75" },
{ label: "B", text: "$12.50" },
{ label: "C", text: "$13.25" },
{ label: "D", text: "$13.75" },
],
correctAnswer: "",
explanation:
"Choice B is correct. Since p represents Megans regular pay per hour, 1.5p represents the pay per hour in excess of 8 hours. Since Megan worked for 10 hours, she must have been paid p dollars per hour for 8 of the hours plus 1.5p dollars per hour for the remaining 2 hours. Therefore, since Megan earned $137.50 for the 10 hours, the situation can be represented by the equation 137.5 = 8p + 2(1.5)p. Distributing the 2 in the equation gives 137.5 = 8p + 3p, and combining like terms gives 137.5 = 11p. Dividing both sides by 11 gives p = 12.5. Therefore, Megans regular wage is $12.50.Choices A and C are incorrect and may be the result of calculation errors. Choice D is incorrect and may result from finding the average hourly wage that Megan earned for the 10 hours of work.",
hasFigure: false,
},
{
id: "45bba652",
type: "mcq",
questionHtml:
"If <strong>2 · (x 5, ) + 3 · (x 5, ) = 10</strong>, what is the value of <strong>x 5</strong> ?",
choices: [
{ label: "A", text: "2" },
{ label: "B", text: "5" },
{ label: "C", text: "7" },
{ label: "D", text: "12" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Adding the like terms on the left-hand side of the given equation yields <strong>5 · (x 5, ) = 10</strong>. Dividing both sides of this equation by 5 yields <strong>x 5 = 2</strong>.Choice B is incorrect and may result from subtracting 5, not dividing by 5, on both sides of the equation <strong>5 · (x 5, ) = 10</strong>. Choice C is incorrect. This is the value of x, not the value of <strong>x 5</strong>. Choice D is incorrect. This is the value of <strong>x + 5</strong>, not the value of <strong>x 5</strong>.",
hasFigure: false,
},
{
id: "4f669597",
type: "spr",
questionHtml: "What value of p is the solution of the equation above?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 1.2. One way to solve the equation <strong>2 · (p + 1, ) + 8 · (p 1, ) = 5 p</strong> is to first distribute the terms outside the parentheses to the terms inside the parentheses: <strong>2 p + 2 + 8 p 8 = 5 p</strong>. Next, combine like terms on the left side of the equal sign: <strong>10 p 6 = 5 p</strong> . Subtracting 10p from both sides yields <strong>6 = 5 p</strong> . Finally, dividing both sides by <strong>5</strong> gives <strong>p = six fifths</strong>, which is equivalent to <strong>p = 1 . 2</strong>. Note that 1.2 and 6/5 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "5a7ab8e8",
type: "mcq",
questionHtml:
"<strong>66 x = 66 x</strong><br>How many solutions does the given equation have?",
choices: [
{ label: "A", text: "Exactly one" },
{ label: "B", text: "Exactly two" },
{ label: "C", text: "Infinitely many" },
{ label: "D", text: "Zero" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. If the two sides of a linear equation are equivalent, then the equation is true for any value. If an equation is true for any value, it has infinitely many solutions. Since the two sides of the given linear equation <strong>66 x = 66 x</strong> are equivalent, the given equation has infinitely many solutions.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "5ad9eff0",
type: "mcq",
questionHtml:
"The width of a rectangular dance floor is w feet. The length of the floor is 6 feet longer than its width. Which of the following expresses the perimeter, in feet, of the dance floor in terms of w ?",
choices: [
{ label: "A", text: "<strong>2 w + 6</strong>" },
{ label: "B", text: "<strong>4 w + 12</strong>" },
{ label: "C", text: "<strong>w² + 6</strong>" },
{ label: "D", text: "<strong>w² + 6 w</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. It is given that the width of the dance floor is w feet. The length is 6 feet longer than the width; therefore, the length of the dance floor is <strong>w + 6</strong>. So the perimeter is <strong>w + w + (w + 6, ) + (w + 6, ) = 4 w + 12</strong>.Choice A is incorrect because it is the sum of one length and one width, which is only half the perimeter. Choice C is incorrect and may result from using the formula for the area instead of the formula for the perimeter and making a calculation error. Choice D is incorrect because this is the area, not the perimeter, of the dance floor.",
hasFigure: false,
},
{
id: "620abf36",
type: "mcq",
questionHtml:
"If <strong>5 (x + 4) = 4 (x + 4) + 29</strong>, what is the value of <strong>x + 4</strong>?",
choices: [
{ label: "A", text: "<strong>4</strong>" },
{ label: "B", text: "<strong>25</strong>" },
{ label: "C", text: "<strong>29</strong>" },
{ label: "D", text: "<strong>33</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Subtracting <strong>4 (x + 4)</strong> from both sides of the given equation yields <strong>1 (x + 4) = 29</strong>, or <strong>x + 4 = 29</strong>. Therefore, the value of <strong>x + 4</strong> is <strong>29</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect. This is the value of <strong>x</strong>, not <strong>x + 4</strong>.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "70e29454",
type: "mcq",
questionHtml:
"In the equation above, a and b are constants. If the equation has infinitely many solutions, what are the values of a and b ?",
choices: [
{ label: "A", text: "<strong>a = 2</strong> and <strong>b = 1</strong>" },
{ label: "B", text: "<strong>a = 2</strong> and <strong>b = 7</strong>" },
{
label: "C",
text: "<strong>a = 2</strong> and <strong>b = 5</strong>",
},
{
label: "D",
text: "<strong>a = 2</strong> and <strong>b = 5</strong>",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. Distributing the a on the left-hand side of the equation gives 3a  b  ax = 1 2x. Rearranging the terms in each side of the equation yields ax + 3a b = 2x 1. Since the equation has infinitely many solutions, it follows that the coefficients of x and the free terms on both sides must be equal. That is,  a = 2, or a = 2, and 3a b = 1. Substituting 2 for a in the equation 3a  b = 1 gives 3(2) b = 1, so  b = 7.Choice A is incorrect and may be the result of a conceptual error when finding the value of b. Choices C and D are incorrect and may result from making a sign error when simplifying.",
hasFigure: false,
},
{
id: "7a5a74a6",
type: "mcq",
questionHtml:
"If x is the solution to the equation above, what is the value of <strong>x 3</strong> ?",
choices: [
{ label: "A", text: "<strong>23 over 2</strong>" },
{ label: "B", text: "<strong>17 over 2</strong>" },
{ label: "C", text: "<strong>15 over 2</strong>" },
{ label: "D", text: "<strong>negative, 15 over 2</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Because 2 is a factor of both <strong>2 x</strong> and 6, the expression <strong>2 x 6</strong> can be rewritten as <strong>2 · (x 3, )</strong>. Substituting <strong>2 · (x 3, )</strong> for <strong>2 x 6</strong> on the left-hand side of the given equation yields <strong>3 · 2 · (x 3, ) 11 = 4 · (x 3, ) + 6</strong>, or <strong>6 · (x 3, ) 11 = 4 · (x 3, ) + 6</strong>. Subtracting <strong>4 · (x 3, )</strong> from both sides of this equation yields <strong>2 · (x 3, ) 11 = 6</strong>. Adding 11 to both sides of this equation yields <strong>2 · (x 3, ) = 17</strong>. Dividing both sides of this equation by 2 yields <strong>x 3 = the fraction 17 over 2</strong>.Alternate approach: Distributing 3 to the quantity <strong>2 x 6</strong> on the left-hand side of the given equation and distributing 4 to the quantity <strong>x 3</strong> on the right-hand side yields <strong>6 x 18 11 = 4 x 12 + 6</strong>, or <strong>6 x 29 = 4 x 6</strong>. Subtracting <strong>4 x</strong> from both sides of this equation yields <strong>2 x 29 = 6</strong>. Adding 29 to both sides of this equation yields <strong>2 x = 23</strong>. Dividing both sides of this equation by 2 yields <strong>x = the fraction 23 over 2</strong>. Therefore, the value of <strong>x 3</strong> is <strong>the fraction 23 over 2, end fraction 3</strong>, or <strong>the fraction 17 over 2</strong>.<br>Choice A is incorrect. This is the value of x, not <strong>x 3</strong>. Choices C and D are incorrect. If the value of <strong>x 3</strong> is <strong>the fraction 15 over 2</strong> or <strong>of the fraction 15 over 2</strong>, it follows that the value of x is <strong>the fraction 21 over 2</strong> or <strong>of the fraction 9 over 2</strong>, respectively. However, solving the given equation for x yields <strong>x = the fraction 23 over 2</strong>. Therefore, the value of <strong>x 3</strong> cant be <strong>the fraction 15 over 2</strong> or <strong>of the fraction 15 over 2</strong>.",
hasFigure: false,
},
{
id: "8c515062",
type: "mcq",
questionHtml:
"A candle is made of <strong>17</strong> ounces of wax. When the candle is burning, the amount of wax in the candle decreases by <strong>1</strong> ounce every <strong>4</strong> hours. If <strong>6</strong> ounces of wax remain in this candle, for how many hours has it been burning?",
choices: [
{ label: "A", text: "<strong>3</strong>" },
{ label: "B", text: "<strong>6</strong>" },
{ label: "C", text: "<strong>24</strong>" },
{ label: "D", text: "<strong>44</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Its given that the candle starts with <strong>17</strong> ounces of wax and has <strong>6</strong> ounces of wax remaining after a period of time has passed. The amount of wax the candle has lost during the time period can be found by subtracting the remaining amount of wax from the amount of wax the candle was made of, which yields <strong>17 6</strong> ounces, or <strong>11</strong> ounces. This means the candle loses <strong>11</strong> ounces of wax during that period of time. Its given that the amount of wax decreases by <strong>1</strong> ounce every <strong>4</strong> hours. If <strong>h</strong> represents the number of hours the candle has been burning, it follows that <strong>one fourth = (11) / (h)</strong>. Multiplying both sides of this equation by <strong>4 h</strong> yields <strong>h = 44</strong>. Therefore, the candle has been burning for <strong>44</strong> hours. <br>Choice A is incorrect and may result from using the equation <strong>one fourth = (h) / (11)</strong> rather than <strong>one fourth = (11) / (h)</strong> to represent the situation, and then rounding to the nearest whole number. <br>Choice B is incorrect. This is the amount of wax, in ounces, remaining in the candle, not the number of hours it has been burning. <br>Choice C is incorrect and may result from using the equation <strong>one fourth = (6) / (h)</strong> rather than <strong>one fourth = (11) / (h)</strong> to represent the situation.",
hasFigure: false,
},
{
id: "aa85b138",
type: "mcq",
questionHtml:
"A tree had a height of 6 feet when it was planted. The equation above can be used to find how many years n it took the tree to reach a height of 14 feet. Which of the following is the best interpretation of the number 2 in this context?",
choices: [
{
label: "A",
text: "The number of years it took the tree to double its height",
},
{
label: "B",
text: "The average number of feet that the tree grew per year",
},
{
label: "C",
text: "The height, in feet, of the tree when the tree was 1 year old",
},
{
label: "D",
text: "The average number of years it takes similar trees to grow 14 feet",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. The height of the tree at a given time is equal to its height when it was planted plus the number of feet that the tree grew. In the given equation, 14 represents the height of the tree at the given time, and 6 represents the height of the tree when it was planted. It follows that <strong>2 n</strong> represents the number of feet the tree grew from the time it was planted until the time it reached a height of 14 feet. Since n represents the number of years between the given time and the time the tree was planted, 2 must represent the average number of feet the tree grew each year.Choice A is incorrect and may result from interpreting the coefficient 2 as doubling instead of as increasing by 2 each year. Choice C is incorrect. The height of the tree when it was 1 year old was <strong>2 · 1 + 6 = 8</strong> feet, not 2 feet. Choice D is incorrect. No information is given to connect the growth of one particular tree to the growth of similar trees.",
hasFigure: false,
},
{
id: "ce314070",
type: "mcq",
questionHtml:
"If <strong>4 x one half = 5</strong>, what is the value of <strong>8 x 1</strong>?",
choices: [
{ label: "A", text: "<strong>2</strong>" },
{ label: "B", text: "<strong>nine eighths</strong>" },
{ label: "C", text: "<strong>five halves</strong>" },
{ label: "D", text: "<strong>10</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Multiplying the given equation by 2 on each side yields <strong>2 · (4 x one half, ) = 2 · 5</strong>. Applying the distributive property, this equation can be rewritten as <strong>2 · 4 x 2 · one half = 2 · 5</strong>, or <strong>8 x 1 = 10</strong>.Choices A, B, and C are incorrect and may result from calculation errors in solving the given equation for <strong>x</strong> and then substituting that value of x in the expression <strong>8 x 1</strong>.",
hasFigure: false,
},
{
id: "ce6b52d8",
type: "spr",
questionHtml:
"If <strong>2 (3 t 10) + t = 40 + 4 t</strong>, what is the value of <strong>3 t</strong>?",
choices: [],
correctAnswer: "60",
explanation:
"The correct answer is <strong>60</strong>. Subtracting <strong>t</strong> from both sides of the given equation yields <strong>2 (3 t 10) = 40 + 3 t</strong>. Applying the distributive property to the left-hand side of this equation yields <strong>6 t 20 = 40 + 3 t</strong>. Adding <strong>20</strong> to both sides of this equation yields <strong>6 t = 60 + 3 t</strong>. Subtracting <strong>3 t</strong> from both sides of this equation yields <strong>3 t = 60</strong>. Therefore, the value of <strong>3 t</strong> is <strong>60</strong>.",
hasFigure: false,
},
{
id: "eafdbbbd",
type: "mcq",
questionHtml:
"<strong>one fourth (x + 5) one third (x + 5) = 7</strong><br>What value of <strong>x</strong> is the solution to the given equation?",
choices: [
{ label: "A", text: "<strong>12</strong>" },
{ label: "B", text: "<strong>5</strong>" },
{ label: "C", text: "<strong>79</strong>" },
{ label: "D", text: "<strong>204</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. For the given equation, <strong>(x + 5)</strong> is a factor of both terms on the left-hand side. Therefore, the given equation can be rewritten as <strong>(one fourth one third) (x + 5) = 7</strong>, or <strong>(three twelfths four twelfths) (x + 5) = 7</strong>, which is equivalent to <strong> one twelfth (x + 5) = 7</strong>. Multiplying both sides of this equation by <strong>12</strong> yields <strong>x + 5 = 84</strong>. Subtracting <strong>5</strong> from both sides of this equation yields <strong>x = 79</strong>. <br>Choice A is incorrect. This is the value of <strong>x</strong> for which the left-hand side of the given equation equals <strong>seven twelfths</strong>, not <strong>7</strong>.<br>Choice B is incorrect. This is the value of <strong>x</strong> for which the left-hand side of the given equation equals <strong>0</strong>, not <strong>7</strong>.<br>Choice D is incorrect. This is the value of <strong>x</strong> for which the left-hand side of the given equation equals <strong>(209) / (12)</strong>, not <strong>7</strong>.",
hasFigure: false,
},
{
id: "f09097b1",
type: "spr",
questionHtml:
"An agricultural scientist studying the growth of corn plants recorded the height of a corn plant at the beginning of a study and the height of the plant each day for the next 12 days. The scientist found that the height of the plant increased by an average of 1.20 centimeters per day for the 12 days. If the height of the plant on the last day of the study was 36.8 centimeters, what was the height, in centimeters, of the corn plant at the beginning of the study?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 22.4. If the height of the plant increased by an average of 1.20 centimeters per day for 12 days, then its total growth over the 12 days was <strong>1 . 2 0 · 12 = 14.4</strong> centimeters. The plant was 36.8 centimeters tall after 12 days, so at the beginning of the study its height was <strong>36 . 8 14 . 4 = 22 . 4</strong> centimeters. Note that 22.4 and 112/5 are examples of ways to enter a correct answer.Alternate approach: The equation <strong>36 . 8 = 12 · 1 . 2 0 + h</strong> can be used to represent this situation, where h is the height of the plant, in centimeters, at the beginning of the study. Solving this equation for h yields 22.4 centimeters.",
hasFigure: false,
},
];
export const LINEAR_EQ_ONE_VAR_HARD: PracticeQuestion[] = [
{
id: "0cb57740",
type: "mcq",
questionHtml:
"Each side of a <strong>30</strong>-sided polygon has one of three lengths. The number of sides with length <strong>8 centimeters (cm)</strong> is <strong>5</strong> times the number of sides <strong>n</strong> with length <strong>3 cm</strong>. There are <strong>6</strong> sides with length <strong>4 cm</strong>. Which equation must be true for the value of <strong>n</strong>?",
choices: [
{ label: "A", text: "<strong>5 n + 6 = 30</strong>" },
{ label: "B", text: "<strong>6 n + 6 = 30</strong>" },
{ label: "C", text: "<strong>8 n + 3 n + 4 n = 30</strong>" },
{ label: "D", text: "<strong>8 (5 n) + 3 n + 4 (6) = 30</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that each side of a <strong>30</strong>-sided polygon has one of three lengths. It's also given that the number of sides with length <strong>8</strong> <strong>centimeters (cm)</strong> is <strong>5</strong> times the number of sides <strong>n</strong> with length <strong>3 cm</strong>. Therefore, there are <strong>5 · n</strong>, or <strong>5 n</strong>, sides with length <strong>8 cm</strong>. Its also given that there are <strong>6</strong> sides with length <strong>4 cm</strong>. Therefore, the number of <strong>3 cm</strong>, <strong>4 cm</strong>, and <strong>8 cm</strong> sides are <strong>n</strong>, <strong>6</strong>, and <strong>5 n</strong>, respectively. Since there are a total of <strong>30</strong> sides, the equation <strong>n + 6 + 5 n = 30</strong> represents this situation. Combining like terms on the left-hand side of this equation yields <strong>6 n + 6 = 30</strong>. Therefore, the equation that must be true for the value of <strong>n</strong> is <strong>6 n + 6 = 30</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "153ee763",
type: "mcq",
questionHtml:
"<strong> 3 x + 21 p x = 84</strong><br>In the given equation, <strong>p</strong> is a constant. The equation has no solution. What is the value of <strong>p</strong>?",
choices: [
{ label: "A", text: "<strong>0</strong>" },
{ label: "B", text: "<strong>one seventh</strong>" },
{ label: "C", text: "<strong>four thirds</strong>" },
{ label: "D", text: "<strong>4</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. A linear equation in one variable has no solution if and only if the equation is false; that is, when there is no value of <strong>x</strong> that produces a true statement. It's given that in the equation <strong> 3 x + 21 p x = 84</strong>, <strong>p</strong> is a constant and the equation has no solution for <strong>x</strong>. Therefore, the value of the constant <strong>p</strong> is one that results in a false equation. Factoring out the common factor of <strong> 3 x</strong> on the left-hand side of the given equation yields <strong> 3 x (1 7 p) = 84</strong>. Dividing both sides of this equation by <strong>3</strong> yields <strong>x (1 7 p) = 28</strong>. Dividing both sides of this equation by <strong>(1 7 p)</strong> yields <strong>x = (28) / (1 7 p)</strong>. This equation is false if and only if <strong>1 7 p = 0</strong>. Adding <strong>7 p</strong> to both sides of <strong>1 7 p = 0</strong> yields <strong>1 = 7 p</strong>. Dividing both sides of this equation by <strong>7</strong> yields <strong>one seventh = p</strong>. It follows that the equation <strong>x = (28) / (1 7 p)</strong> is false if and only if <strong>p = one seventh</strong>. Therefore, the given equation has no solution if and only if the value of <strong>p</strong> is <strong>one seventh</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "25e1cfed",
type: "mcq",
questionHtml:
"How many solutions does the equation <strong>10 (15 x 9) = 15 (6 10 x)</strong> have?",
choices: [
{ label: "A", text: "Exactly one" },
{ label: "B", text: "Exactly two" },
{ label: "C", text: "Infinitely many" },
{ label: "D", text: "Zero" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Applying the distributive property to each side of the given equation yields <strong>150 x 90 = 90 + 150 x</strong>. Applying the commutative property of addition to the right-hand side of this equation yields <strong>150 x 90 = 150 x 90</strong>. Since the two sides of the equation are equivalent, this equation is true for any value of <strong>x</strong>. Therefore, the given equation has infinitely many solutions.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "2937ef4f",
type: "mcq",
questionHtml:
"Hector used a tool called an auger to remove corn from a storage bin at a constant rate. The bin contained 24,000 bushels of corn when Hector began to use the auger. After 5 hours of using the auger, 19,350 bushels of corn remained in the bin. If the auger continues to remove corn at this rate, what is the total number of hours Hector will have been using the auger when 12,840 bushels of corn remain in the bin?",
choices: [
{ label: "A", text: "3" },
{ label: "B", text: "7" },
{ label: "C", text: "8" },
{ label: "D", text: "12" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. After using the auger for 5 hours, Hector had removed 24,000 19,350 = 4,650 bushels of corn from the storage bin. During the 5-hour period, the auger removed corn from the bin at a constant rate of <strong>the fraction 4, 650 over 5 = 930</strong> bushels per hour. Assuming the auger continues to remove corn at this rate, after x hours it will have removed 930x bushels of corn. Because the bin contained 24,000 bushels of corn when Hector started using the auger, the equation 24,000 930x = 12,840 can be used to find the number of hours, x, Hector will have been using the auger when 12,840 bushels of corn remain in the bin. Subtracting 12,840 from both sides of this equation and adding 930x to both sides of the equation yields 11,160 = 930x. Dividing both sides of this equation by 930 yields x = 12. Therefore, Hector will have been using the auger for 12 hours when 12,840 bushels of corn remain in the storage bin.<br> Choice A is incorrect. Three hours after Hector began using the auger, 24,000 3(930) = 21,210 bushels of corn remained, not 12,840. Choice B is incorrect. Seven hours after Hector began using the auger, 24,000 7(930) = 17,490 bushels of corn will remain, not 12,840. Choice C is incorrect. Eight hours after Hector began using the auger, 24,000 8(930) = 16,560 bushels of corn will remain, not 12,840.",
hasFigure: false,
},
{
id: "3f8a701b",
type: "mcq",
questionHtml:
"The equation <strong>9 x + 5 = a · (x + b, )</strong>, where a and b are constants, has no solutions. Which of the following must be true?<br> I. <strong>a = 9</strong><br> <br><br> II. <strong>b = 5</strong><br> <br><br> III. <strong>b ≠ five ninths</strong>",
choices: [
{ label: "A", text: "None" },
{ label: "B", text: "I only" },
{ label: "C", text: "I and II only" },
{ label: "D", text: "I and III only" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. For a linear equation in a form <strong>a, x + b = c x + d</strong> to have no solutions, the x-terms must have equal coefficients and the remaining terms must not be equal. Expanding the right-hand side of the given equation yields <strong>9 x + 5 = a, x + a, b</strong>. Inspecting the x-terms, 9 must equal a, so statement I must be true. Inspecting the remaining terms, 5 cant equal <strong>9 b</strong>. Dividing both of these quantities by 9 yields that b cant equal <strong>five ninths</strong>. Therefore, statement III must be true. Since b can have any value other than <strong>five ninths</strong>, statement II may or may not be true.Choice A is incorrect. For the given equation to have no solution, both <strong>a = 9</strong> and <strong>b ≠ five ninths</strong> must be true. Choice B is incorrect because it must also be true that <strong>b ≠ five ninths</strong>. Choice C is incorrect because when <strong>a = 9</strong>, there are many values of b that lead to an equation having no solution. That is, b might be 5, but b isnt required to be 5.",
hasFigure: false,
},
{
id: "628300a9",
type: "mcq",
questionHtml:
"A science teacher is preparing the 5 stations of a science laboratory. Each station will have either Experiment A materials or Experiment B materials, but not both. Experiment A requires 6 teaspoons of salt, and Experiment B requires 4 teaspoons of salt. If x is the number of stations that will be set up for Experiment A and the remaining stations will be set up for Experiment B, which of the following expressions represents the total number of teaspoons of salt required?",
choices: [
{ label: "A", text: "<strong>5 x</strong>" },
{ label: "B", text: "<strong>10 x</strong>" },
{ label: "C", text: "<strong>2 x + 20</strong>" },
{ label: "D", text: "<strong>10 x + 20</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. It is given that x represents the number of stations that will be set up for Experiment A and that there will be 5 stations total, so it follows that 5 x is the number of stations that will be set up for Experiment B. It is also given that Experiment A requires 6 teaspoons of salt and that Experiment B requires 4 teaspoons of salt, so the total number of teaspoons of salt required is 6x + 4(5 x), which simplifies to 2x + 20.Choices A, B, and D are incorrect and may be the result of not understanding the description of the context.",
hasFigure: false,
},
{
id: "771bd0ca",
type: "spr",
questionHtml:
"<strong>5 (t + 3) 7 (t + 3) = 38</strong><br>What value of <strong>t</strong> is the solution to the given equation?",
choices: [],
correctAnswer: "-22",
explanation:
"The correct answer is <strong>22</strong>. The given equation can be rewritten as <strong> 2 (t + 3) = 38</strong>. Dividing both sides of this equation by <strong>2</strong> yields <strong>t + 3 = 19</strong>. Subtracting <strong>3</strong> from both sides of this equation yields <strong>t = 22</strong>. Therefore, <strong>22</strong> is the value of <strong>t</strong> that is the solution to the given equation.",
hasFigure: false,
},
{
id: "7d5d1b32",
type: "spr",
questionHtml:
"<strong>2 (k x n) = (28) / (15) x (36) / (19)</strong><br>In the given equation, <strong>k</strong> and <strong>n</strong> are constants and <strong>n > 1</strong>. The equation has no solution. What is the value of <strong>k</strong>?",
choices: [],
correctAnswer: "-.9333, -14/15",
explanation:
"The correct answer is <strong>(14) / (15)</strong>. A linear equation in the form <strong>a x + b = c x + d</strong> has no solution only when the coefficients of <strong>x</strong> on each side of the equation are equal and the constant terms are not equal. Dividing both sides of the given equation by <strong>2</strong> yields <strong>k x n = (28) / (30) x (36) / (38)</strong>, or <strong>k x n = (14) / (15) x (18) / (19)</strong>. Since its given that the equation has no solution, the coefficient of <strong>x</strong> on both sides of this equation must be equal, and the constant terms on both sides of this equation must not be equal. Since <strong>(18) / (19) < 1</strong>, and it's given that <strong>n > 1</strong>, the second condition is true. Thus, <strong>k</strong> must be equal to <strong>(14) / (15)</strong>. Note that -14/15, -.9333, and -0.933 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "90095507",
type: "mcq",
questionHtml:
"The Townsend Realty Group invested in the five different properties listed in the table above. The table shows the amount, in dollars, the company paid for each property and the corresponding monthly rental price, in dollars, the company charges for the property at each of the five locations. Townsend Realty purchased the Glenview Street property and received a 40% discount off the original price along with an additional 20% off the discounted price for purchasing the property in cash. Which of the following best approximates the original price, in dollars, of the Glenview Street property?",
choices: [
{ label: "A", text: "$350,000" },
{ label: "B", text: "$291,700" },
{ label: "C", text: "$233,300" },
{ label: "D", text: "$175,000" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Let x be the original price, in dollars, of the Glenview Street property. After the 40% discount, the price of the property became <strong>0 . 6 x</strong> dollars, and after the additional 20% off the discounted price, the price of the property became <strong>0 . 8 · 0 . 6 x</strong>. Thus, in terms of the original price of the property, x, the purchase price of the property is <strong>0 . 4 8 x</strong> . It follows that <strong>0 . 4 8 x = 140, 000</strong>. Solving this equation for x gives <strong>x = 291, 666 . 6, with the 6 repeating after the decimal .</strong>. Therefore, of the given choices, $291,700 best approximates the original price of the Glenview Street property.Choice A is incorrect because it is the result of dividing the purchase price of the property by 0.4, as though the purchase price were 40% of the original price. Choice C is incorrect because it is the closest to dividing the purchase price of the property by 0.6, as though the purchase price were 60% of the original price. Choice D is incorrect because it is the result of dividing the purchase price of the property by 0.8, as though the purchase price were 80% of the original price.",
hasFigure: false,
},
{
id: "ae2287e2",
type: "mcq",
questionHtml:
"A certain product costs a company $65 to make. The product is sold by a salesperson who earns a commission that is equal to 20% of the sales price of the product. The profit the company makes for each unit is equal to the sales price minus the combined cost of making the product and the commission. If the sales price of the product is $100, which of the following equations gives the number of units, u, of the product the company sold to make a profit of $6,840 ?",
choices: [
{ label: "A", text: "[]" },
{ label: "B", text: "[]" },
{ label: "C", text: "<strong>0 . 8 · 100 65 u = 6, 840</strong>" },
{ label: "D", text: "[]" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The sales price of one unit of the product is given as $100. Because the salesperson is awarded a commission equal to 20% of the sales price, the expression 100(1 0.2) gives the sales price of one unit after the commission is deducted. It is also given that the profit is equal to the sales price minus the combined cost of making the product, or $65, and the commission: 100(1 0.2) 65. Multiplying this expression by u gives the profit of u units: (100(1 0.2) 65)u. Finally, it is given that the profit for u units is $6,840; therefore (100(1 0.2) 65)u = $6,840.Choice B is incorrect. In this equation, cost is subtracted before commission and the equation gives the commission, not what the company retains after commission. Choice C is incorrect because the number of units is multiplied only by the cost but not by the sale price. Choice D is incorrect because the value 0.2 shows the commission, not what the company retains after commission.",
hasFigure: false,
},
{
id: "aee9fd2d",
type: "mcq",
questionHtml:
"If <strong>(x + 6) / (3) = (x + 6) / (13)</strong>, the value of <strong>x + 6</strong> is between which of the following pairs of values?",
choices: [
{ label: "A", text: "<strong>7</strong> and <strong>3</strong>" },
{ label: "B", text: "<strong>2</strong> and <strong>2</strong>" },
{ label: "C", text: "<strong>2</strong> and <strong>7</strong>" },
{ label: "D", text: "<strong>8</strong> and <strong>13</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Multiplying both sides of the given equation by <strong>(3) (13)</strong>, or <strong>39</strong>, yields <strong>(39) ((x + 6) / (3)) = (39) ((x + 6) / (13))</strong>, or <strong>13 (x + 6) = 3 (x + 6)</strong>. Subtracting <strong>3 (x + 6)</strong> from both sides of this equation yields <strong>10 (x + 6) = 0</strong>. Dividing both sides of this equation by <strong>10</strong> yields <strong>x + 6 = 0</strong>. Therefore, if <strong>(x + 6) / (3) = (x + 6) / (13)</strong>, then the value of <strong>x + 6</strong> is <strong>0</strong>. It follows that of the given choices, the value of <strong>x + 6</strong> is between <strong>2</strong> and <strong>2</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "b7e6394d",
type: "mcq",
questionHtml:
"Alan drives an average of 100 miles each week. His car can travel an average of 25 miles per gallon of gasoline. Alan would like to reduce his weekly expenditure on gasoline by $5. Assuming gasoline costs $4 per gallon, which equation can Alan use to determine how many fewer average miles, m, he should drive each week?",
choices: [
{
label: "A",
text: "<strong>the fraction 25 over 4, end fraction · m = 95</strong>",
},
{
label: "B",
text: "<strong>the fraction 25 over 4, end fraction · m = 5</strong>",
},
{
label: "C",
text: "<strong>the fraction 4 over 25, end fraction · m = 95</strong>",
},
{
label: "D",
text: "<strong>the fraction 4 over 25, end fraction · m = 5</strong>",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. Since gasoline costs $4 per gallon, and since Alans car travels an average of 25 miles per gallon, the expression <strong>4 over 25</strong> gives the cost, in dollars per mile, to drive the car. Multiplying <strong>4 over 25</strong> by m gives the cost for Alan to drive m miles in his car. Alan wants to reduce his weekly spending by $5, so setting <strong>4 over 25</strong>m equal to 5 gives the number of miles, m, by which he must reduce his driving.Choices A, B, and C are incorrect. Choices A and B transpose the numerator and the denominator in the fraction. The fraction <strong>25 over 4</strong> would result in the unit miles per dollar, but the question requires a unit of dollars per mile. Choices A and C set the expression equal to 95 instead of 5, a mistake that may result from a misconception that Alan wants to reduce his driving by 5 miles each week; instead, the question says he wants to reduce his weekly expenditure by $5.",
hasFigure: false,
},
{
id: "e6cb2402",
type: "spr",
questionHtml:
"<strong>3 (k x + 13) = (48) / (17) x + 36</strong><br>In the given equation, <strong>k</strong> is a constant. The equation has no solution. What is the value of <strong>k</strong>?",
choices: [],
correctAnswer: ".9411, .9412, 16/17",
explanation:
"The correct answer is <strong>(16) / (17)</strong>. It's given that the equation <strong>3 (k x + 13) = (48) / (17) x + 36</strong> has no solution. A linear equation in the form <strong>a x + b = c x + d</strong>, where <strong>a</strong>, <strong>b</strong>, <strong>c</strong>, and <strong>d</strong> are constants, has no solution only when the coefficients of <strong>x</strong> on each side of the equation are equal and the constant terms aren't equal. Dividing both sides of the given equation by <strong>3</strong> yields <strong>k x + 13 = (48) / (51) x + (36) / (3)</strong>, or <strong>k x + 13 = (16) / (17) x + 12</strong>. Since the coefficients of <strong>x</strong> on each side of the equation must be equal, it follows that the value of <strong>k</strong> is <strong>(16) / (17)</strong>. Note that 16/17, .9411, .9412, and 0.941 are examples of ways to enter a correct answer.",
hasFigure: false,
},
];

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,822 @@
import { type PracticeQuestion } from "../../types/lesson";
export const LINEAR_INEQ_EASY: PracticeQuestion[] = [
{
id: "2c121b25",
type: "mcq",
questionHtml:
"Valentina bought two containers of beads. In the first container 30% of the beads are red, and in the second container 70% of the beads are red. Together, the containers have at least 400 red beads. Which inequality shows this relationship, where x is the total number of beads in the first container and y is the total number of beads in the second container?",
choices: [
{ label: "A", text: "<strong>0 . 3 x + 0 . 7 y ≥ 400</strong>" },
{ label: "B", text: "<strong>0 . 7 x + 0 . 3 y ≤ 400</strong>" },
{
label: "C",
text: "<strong>the fraction x over 3, end fraction + the fraction y over 7, end fraction ≤ 400</strong>",
},
{ label: "D", text: "<strong>30 x + 70 y ≥ 400</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. It is given that x is the total number of beads in the first container and that 30% of those beads are red; therefore, the expression 0.3x represents the number of red beads in the first container. It is given that y is the total number of beads in the second container and that 70% of those beads are red; therefore, the expression 0.7y represents the number of red beads in the second container. It is also given that, together, the containers have at least 400 red beads, so the inequality that shows this relationship is 0.3x + 0.7y ≥ 400.Choice B is incorrect because it represents the containers having a total of at most, rather than at least, 400 red beads. Choice C is incorrect and may be the result of misunderstanding how to represent a percentage of beads in each container. Also, the inequality shows the containers having a combined total of at most, rather than at least, 400 red beads. Choice D is incorrect because the percentages were not converted to decimals.",
hasFigure: false,
},
{
id: "563407e5",
type: "mcq",
questionHtml:
"A bakery sells trays of cookies. Each tray contains at least 50 cookies but no more than 60. Which of the following could be the total number of cookies on 4 trays of cookies?",
choices: [
{ label: "A", text: "165" },
{ label: "B", text: "205" },
{ label: "C", text: "245" },
{ label: "D", text: "285" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. If each tray contains the least number of cookies possible, 50 cookies, then the least number of cookies possible on 4 trays is 50 × 4 = 200 cookies. If each tray contains the greatest number of cookies possible, 60 cookies, then the greatest number of cookies possible on 4 trays is 60 × 4 = 240 cookies. If the least number of cookies on 4 trays is 200 and the greatest number of cookies is 240, then 205 could be the total number of cookies on these 4 trays of cookies because <strong>200 ≤ 205, which ≤ 240.</strong>.Choices A, C, and D are incorrect. The least number of cookies on 4 trays is 200 cookies, and the greatest number of cookies on 4 trays is 240 cookies. The choices 165, 245, and 285 are each either less than 200 or greater than 240; therefore, they cannot represent the total number of cookies on 4 trays.",
hasFigure: false,
},
{
id: "59a49431",
type: "mcq",
questionHtml:
"The boundary of the inequality is a solid line.<br><br>The line slants sharply down from left to right.<br>The line passes through the following points:<br><br>(1.0 comma 6.5)<br>(3.0 comma negative 4.5)<br><br>The area above and to the right of the boundary is shaded.<br><br>The shaded region shown represents solutions to an inequality. Which ordered pair <strong>(x, y)</strong> is a solution to this inequality?",
choices: [
{ label: "A", text: "<strong>(0 4)</strong>" },
{ label: "B", text: "<strong>(0, 4)</strong>" },
{ label: "C", text: "<strong>(4, 0)</strong>" },
{ label: "D", text: "<strong>(4, 0)</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Since the shaded region shown represents solutions to an inequality, an ordered pair <strong>(x, y)</strong> is a solution to the inequality if it's represented by a point in the shaded region. Of the given choices, only <strong>(4, 0)</strong> is represented by a point in the shaded region. Therefore, <strong>(4, 0)</strong> is a solution to the inequality.<br>Choice A is incorrect and may result from conceptual errors.<br>Choice B is incorrect and may result from conceptual errors.<br>Choice C is incorrect and may result from conceptual errors.",
hasFigure: true,
figureUrl: "/practice-images/59a49431_svg1.svg",
},
{
id: "68f2cbaf",
type: "mcq",
questionHtml:
"Ty set a goal to walk at least <strong>24</strong> kilometers every day to prepare for a multiday hike. On a certain day, Ty plans to walk at an average speed of <strong>4</strong> kilometers per hour. What is the minimum number of hours Ty must walk on that day to fulfill the daily goal?",
choices: [
{ label: "A", text: "<strong>4</strong>" },
{ label: "B", text: "<strong>6</strong>" },
{ label: "C", text: "<strong>20</strong>" },
{ label: "D", text: "<strong>24</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. It's given that Ty plans to walk at an average speed of <strong>4</strong> kilometers per hour. The number of kilometers Ty will walk is determined by the expression <strong>4 s</strong>, where <strong>s</strong> is the number of hours Ty walks. The given goal of at least <strong>24</strong> kilometers means that the inequality <strong>4 s > or = 24</strong> represents the situation. Dividing both sides of this inequality by <strong>4</strong> gives <strong>s > or = 6</strong> , which corresponds to a minimum of <strong>6</strong> hours Ty must walk. <br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "7d6928bd",
type: "mcq",
questionHtml:
"A cleaning service that cleans both offices and homes can clean at most <strong>14</strong> places per day. Which inequality represents this situation, where <strong>f</strong> is the number of offices and <strong>h</strong> is the number of homes?",
choices: [
{ label: "A", text: "<strong>f + h < or = 14</strong>" },
{ label: "B", text: "<strong>f + h > or = 14</strong>" },
{ label: "C", text: "<strong>f h < or = 14</strong>" },
{ label: "D", text: "<strong>f h > or = 14</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. It's given that the cleaning service cleans both offices and homes, where <strong>f</strong> is the number of offices and <strong>h</strong> is the number of homes the cleaning service can clean per day. Therefore, the expression <strong>f + h</strong> represents the number of places the cleaning service can clean per day. It's also given that the cleaning service can clean at most <strong>14</strong> places per day. Since <strong>f + h</strong> represents the number of places the cleaning service can clean per day and the service can clean at most <strong>14</strong> places per day, it follows that the inequality <strong>f + h < or = 14</strong> represents this situation.<br>Choice B is incorrect. This inequality represents a cleaning service that cleans at least <strong>14</strong> places per day.<br>Choice C is incorrect. This inequality represents a cleaning service that cleans at most <strong>14</strong> more offices than homes per day.<br>Choice D is incorrect. This inequality represents a cleaning service that cleans at least <strong>14</strong> more offices than homes per day.",
hasFigure: false,
},
{
id: "84d0d07e",
type: "mcq",
questionHtml:
"A clothing store is having a sale on shirts and pants. During the sale, the cost of each shirt is $15 and the cost of each pair of pants is $25. Geoff can spend at most $120 at the store. If Geoff buys s shirts and p pairs of pants, which of the following must be true?",
choices: [
{ label: "A", text: "<strong>15 s + 25 p ≤ 120</strong>" },
{ label: "B", text: "<strong>15 s + 25 p ≥ 120</strong>" },
{ label: "C", text: "<strong>25 s + 15 p ≤ 120</strong>" },
{ label: "D", text: "<strong>25 s + 15 p ≥ 120</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Since the cost of each shirt is $15 and Geoff buys s shirts, the expression <strong>15 s</strong> represents the amount Geoff spends on shirts. Since the cost of each pair of pants is $25 and Geoff buys p pairs of pants, the expression <strong>25 p</strong> represents the amount Geoff spends on pants. Therefore, the sum <strong>15 s + 25 p</strong> represents the total amount Geoff spends at the store. Since Geoff can spend at most $120 at the store, the total amount he spends must be less than or equal to 120. Thus, <strong>15 s + 25 p ≤ 120</strong>.Choice B is incorrect. This represents the situation in which Geoff spends at least, rather than at most, $120 at the store. Choice C is incorrect and may result from reversing the cost of a shirt and that of a pair of paints. Choice D is incorrect and may result from both reversing the cost of a shirt and that of a pair of pants and from representing a situation in which Geoff spends at least, rather than at most, $120 at the store.",
hasFigure: false,
},
{
id: "89541f9b",
type: "mcq",
questionHtml:
"Which of the following ordered pairs <strong>x, y</strong> satisfies the inequality <strong>5 x 3 y < 4</strong> ?<br> <br> <br> <strong>Statement 1, 1, 1</strong><br> <br> <br> <br> <br> <br> <strong>Statement 2, 2, 5</strong><br> <br> <br> <br> <br> <br> <strong>Statement 3, 3, 2</strong>",
choices: [
{ label: "A", text: "I only" },
{ label: "B", text: "II only" },
{ label: "C", text: "I and II only" },
{ label: "D", text: "I and III only" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Substituting <strong>the ordered pair 1, 1</strong> into the inequality gives <strong>5 · 1 3 · 1 < 4</strong>, or <strong>2 < 4</strong>, which is a true statement. Substituting <strong>the ordered pair 2, 5</strong> into the inequality gives <strong>5 · 2 3 · 5 < 4</strong>, or <strong>5 < 4</strong>, which is a true statement. Substituting <strong>the ordered pair 3, 2</strong> into the inequality gives <strong>5 · 3 3 · 2 < 4</strong>, or <strong>9 < 4</strong>, which is not a true statement. Therefore, <strong>the ordered pair 1, 1</strong> and <strong>the ordered pair 2, 5</strong> are the only ordered pairs shown that satisfy the given inequality.Choice A is incorrect because the ordered pair <strong>2, 5</strong> also satisfies the inequality. Choice B is incorrect because the ordered pair <strong>1, 1</strong> also satisfies the inequality. Choice D is incorrect because the ordered pair <strong>3, 2</strong> does not satisfy the inequality.",
hasFigure: false,
},
{
id: "915463e0",
type: "mcq",
questionHtml:
"Normal body temperature for an adult is between <strong>97 . 8 ° Fahrenheit</strong> and <strong>99 ° Fahrenheit</strong>, inclusive. If Kevin, an adult male, has a body temperature that is considered to be normal, which of the following could be his body temperature?",
choices: [
{ label: "A", text: "<strong>96 . 7 ° Fahrenheit</strong>" },
{ label: "B", text: "<strong>97 . 6 ° Fahrenheit</strong>" },
{ label: "C", text: "<strong>97 . 9 ° Fahrenheit</strong>" },
{ label: "D", text: "<strong>99 . 7 ° Fahrenheit</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Normal body temperature must be greater than or equal to 97.8°F but less than or equal to 99°F. Of the given choices, 97.9°F is the only temperature that fits these restrictions.Choices A and B are incorrect. These temperatures are less than 97.8°F, so they dont fit the given restrictions. Choice D is incorrect. This temperature is greater than 99°F, so it doesnt fit the given restrictions.",
hasFigure: false,
},
{
id: "b64e2c7f",
type: "mcq",
questionHtml:
"Monarch butterflies can fly only with a body temperature of at least <strong>55.0 ° Fahrenheit (° F)</strong>. If a monarch butterfly's body temperature is <strong>51.3 ° F</strong>, what is the minimum increase needed in its body temperature, in <strong>° F</strong>, so that it can fly?",
choices: [
{ label: "A", text: "<strong>1.3</strong>" },
{ label: "B", text: "<strong>3.7</strong>" },
{ label: "C", text: "<strong>5.0</strong>" },
{ label: "D", text: "<strong>6.3</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. It's given that monarch butterflies can fly only with a body temperature of at least <strong>55.0 ° Fahrenheit (° F)</strong>. Let <strong>x</strong> represent the minimum increase needed in the monarch butterfly's body temperature to fly. If the monarch butterfly's body temperature is <strong>51.3 ° F</strong>, the inequality <strong>51.3 + x > or = 55.0</strong> represents this situation. Subtracting <strong>51.3</strong> from both sides of this inequality yields <strong>x > or = 3.7</strong>. Therefore, if the monarch butterfly's body temperature is <strong>51.3 ° F</strong>, the minimum increase needed in its body temperature, in <strong>° F</strong>, so that it can fly is <strong>3.7</strong>.<br>Choice A is incorrect. This is the minimum increase needed in body temperature if the monarch butterfly's body temperature is <strong>53.7 ° F</strong>, not <strong>51.3 ° F</strong>.<br>Choice C is incorrect. This is the minimum increase needed in body temperature if the monarch butterfly's body temperature is <strong>50.0 ° F</strong>, not <strong>51.3 ° F</strong>.<br>Choice D is incorrect. This is the minimum increase needed in body temperature if the monarch butterfly's body temperature is <strong>48.7 ° F</strong>, not <strong>51.3 ° F</strong>.",
hasFigure: false,
},
{
id: "b75f7812",
type: "spr",
questionHtml:
"Maria plans to rent a boat. The boat rental costs $60 per hour, and she will also have to pay for a water safety course that costs $10. Maria wants to spend no more than $280 for the rental and the course. If the boat rental is available only for a whole number of hours, what is the maximum number of hours for which Maria can rent the boat?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 4. The equation <strong>60 h + 10 ≤ 280</strong>, where h is the number of hours the boat has been rented, can be written to represent the situation. Subtracting 10 from both sides and then dividing by 60 yields <strong>h ≤ 4 . 5</strong>. Since the boat can be rented only for whole numbers of hours, the maximum number of hours for which Maria can rent the boat is 4.",
hasFigure: false,
},
{
id: "c50ede6d",
type: "mcq",
questionHtml:
"The total cost, in dollars, to rent a surfboard consists of a <strong>dollar sign 25</strong> service fee and a <strong>dollar sign 10</strong> per hour rental fee. A person rents a surfboard for <strong>t</strong> hours and intends to spend a maximum of <strong>dollar sign 75</strong> to rent the surfboard. Which inequality represents this situation?",
choices: [
{ label: "A", text: "<strong>10 t < or = 75</strong>" },
{ label: "B", text: "<strong>10 + 25 t < or = 75</strong>" },
{ label: "C", text: "<strong>25 t < or = 75</strong>" },
{ label: "D", text: "<strong>25 + 10 t < or = 75</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The cost of the rental fee depends on the number of hours the surfboard is rented. Multiplying <strong>t</strong> hours by <strong>10</strong> dollars per hour yields a rental fee of <strong>10 t</strong> dollars. The total cost of the rental consists of the rental fee plus the <strong>25</strong> dollar service fee, which yields a total cost of <strong>25 + 10 t</strong> dollars. Since the person intends to spend a maximum of <strong>75</strong> dollars to rent the surfboard, the total cost must be at most <strong>75</strong> dollars. Therefore, the inequality <strong>25 + 10 t < or = 75</strong> represents this situation.<br>Choice A is incorrect. This represents a situation where the rental fee, not the total cost, is at most <strong>75</strong> dollars.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "cfe67646",
type: "mcq",
questionHtml:
"The point <strong>(8, 2)</strong> in the xy-plane is a solution to which of the following systems of inequalities?",
choices: [
{ label: "A", text: "<strong>x > 0</strong><br><strong>y > 0</strong>" },
{ label: "B", text: "<strong>x > 0</strong><br><strong>y < 0</strong>" },
{ label: "C", text: "<strong>x < 0</strong><br><strong>y > 0</strong>" },
{ label: "D", text: "<strong>x < 0</strong><br><strong>y < 0</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The given point, <strong>(8, 2)</strong>, is located in the first quadrant in the xy-plane. The system of inequalities in choice A represents all the points in the first quadrant in the xy-plane. Therefore, <strong>(8, 2)</strong> is a solution to the system of inequalities in choice A.<br>Alternate approach: Substituting <strong>8</strong> for <strong>x</strong> in the first inequality in choice A, <strong>x > 0</strong>, yields <strong>8 > 0</strong>, which is true. Substituting <strong>2</strong> for <strong>y</strong> in the second inequality in choice A, <strong>y > 0</strong>, yields <strong>2 > 0</strong>, which is true. Since the coordinates of the point <strong>(8, 2)</strong> make the inequalities <strong>x > 0</strong> and <strong>y > 0</strong> true, the point <strong>(8, 2)</strong> is a solution to the system of inequalities consisting of <strong>x > 0</strong> and <strong>y > 0</strong>.<br>Choice B is incorrect. This system of inequalities represents all the points in the fourth quadrant, not the first quadrant, in the xy-plane.<br>Choice C is incorrect. This system of inequalities represents all the points in the second quadrant, not the first quadrant, in the xy-plane.<br>Choice D is incorrect. This system of inequalities represents all the points in the third quadrant, not the first quadrant, in the xy-plane.",
hasFigure: false,
},
{
id: "df32b09c",
type: "mcq",
questionHtml:
"Tom scored 85, 78, and 98 on his first three exams in history class. Solving which inequality gives the score, G, on Toms fourth exam that will result in a mean score on all four exams of at least 90 ?",
choices: [
{ label: "A", text: "<strong>90 (85 + 78 + 98, ) ≤ 4 G</strong>" },
{ label: "B", text: "<strong>4 G + 85 + 78 + 98 ≥ 360</strong>" },
{
label: "C",
text: "<strong>the fraction with numerator, (G + 85 + 78 + 98, ), and denominator 4, end fraction ≥ 90</strong>",
},
{
label: "D",
text: "<strong>the fraction with numerator, (85 + 78 + 98, ), and denominator 4, end fraction ≥ 90 4 G</strong>",
},
],
correctAnswer: "C",
explanation:
"Choice C is correct. The mean of the four scores (G, 85, 78, and 98) can be expressed as  <strong>the fraction with numerator G + 85 + 78 + 98, and denominator 4</strong>. The inequality that expresses the condition that the mean score is at least 90 can therefore be written as <strong>the fraction with numerator G + 85 + 78 + 98, and denominator 4 ≥ 90</strong>.Choice A is incorrect. The sum of the scores (G, 85, 78, and 98) isnt divided by 4 to express the mean. Choice B is incorrect and may be the result of an algebraic error when multiplying both sides of the inequality by 4. Choice D is incorrect because it doesnt include G in the mean with the other three scores.",
hasFigure: false,
},
{
id: "e744499e",
type: "mcq",
questionHtml:
"An elementary school teacher is ordering x workbooks and y sets of flash cards for a math class. The teacher must order at least 20 items, but the total cost of the order must not be over $80. If the workbooks cost $3 each and the flash cards cost $4 per set, which of the following systems of inequalities models this situation?",
choices: [
{ label: "A", text: "<strong>x + y ≥ 20, and, 3 x + 4 y ≤ 80</strong>" },
{ label: "B", text: "<strong>x + y ≥ 20, and, 3 x + 4 y ≥ 80</strong>" },
{ label: "C", text: "<strong>3 x + 4 y ≤ 20, and, x + y ≥ 80</strong>" },
{ label: "D", text: "<strong>x + y ≤ 20, and, 3 x + 4 y ≥ 80</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The total number of workbooks and sets of flash cards ordered is represented by x + y. Since the teacher must order at least 20 items, it must be true that x + y ≥ 20. Each workbook costs $3; therefore, 3x represents the cost, in dollars, of x workbooks. Each set of flashcards costs $4; therefore, 4y represents the cost, in dollars, of y sets of flashcards. It follows that the total cost for x workbooks and y sets of flashcards is 3x + 4y. Since the total cost of the order must not be over $80, it must also be true that 3x + 4y ≤ 80. Of the choices given, these inequalities are shown only in choice A.<br> <br><br>Choice B is incorrect. The second inequality says that the total cost must be greater, not less than or equal to $80. Choice C incorrectly limits the cost by the minimum number of items and the number of items with the maximum cost. Choice D is incorrect. The first inequality incorrectly says that at most 20 items must be ordered, and the second inequality says that the total cost of the order must be at least, not at most, $80.",
hasFigure: false,
},
{
id: "ee439cff",
type: "mcq",
questionHtml:
"On a car trip, Rhett and Jessica each drove for part of the trip, and the total distance they drove was under <strong>220</strong> miles. Rhett drove at an average speed of <strong>35 miles per hour (mph)</strong>, and Jessica drove at an average speed of <strong>40 mph</strong>. Which of the following inequalities represents this situation, where <strong>r</strong> is the number of hours Rhett drove and <strong>j</strong> is the number of hours Jessica drove?",
choices: [
{ label: "A", text: "<strong>35 r + 40 j > 220</strong>" },
{ label: "B", text: "<strong>35 r + 40 j < 220</strong>" },
{ label: "C", text: "<strong>40 r + 35 j > 220</strong>" },
{ label: "D", text: "<strong>40 r + 35 j < 220</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that Rhett drove at an average speed of <strong>35</strong> miles per hour and that he drove for <strong>r</strong> hours. Multiplying <strong>35</strong> miles per hour by <strong>r</strong> hours yields <strong>35 r</strong> miles, or the distance that Rhett drove. Its also given that Jessica drove at an average speed of <strong>40</strong> miles per hour and that she drove for <strong>j</strong> hours. Multiplying <strong>40</strong> miles per hour by <strong>j</strong> hours yields <strong>40 j</strong> miles, or the distance that Jessica drove. The total distance, in miles, that Rhett and Jessica drove can be represented by the expression <strong>35 r + 40 j</strong>. Its given that the total distance they drove was under <strong>220</strong> miles. Therefore, the inequality <strong>35 r + 40 j < 220</strong> represents this situation.<br>Choice A is incorrect. This inequality represents a situation in which the total distance Rhett and Jessica drove was over, rather than under, <strong>220</strong> miles.<br>Choice C is incorrect. This inequality represents a situation in which Rhett drove at an average speed of <strong>40</strong>, rather than <strong>35</strong>, miles per hour, Jessica drove at an average speed of <strong>35</strong>, rather than <strong>40</strong>, miles per hour, and the total distance they drove was over, rather than under, <strong>220</strong> miles.<br>Choice D is incorrect. This inequality represents a situation in which Rhett drove at an average speed of <strong>40</strong>, rather than <strong>35</strong>, miles per hour, and Jessica drove at an average speed of <strong>35</strong>, rather than <strong>40</strong>, miles per hour.",
hasFigure: false,
},
];
export const LINEAR_INEQ_MEDIUM: PracticeQuestion[] = [
{
id: "64c85440",
type: "mcq",
questionHtml:
"In North America, the standard width of a parking space is at least 7.5 feet and no more than 9.0 feet. A restaurant owner recently resurfaced the restaurants parking lot and wants to determine the number of parking spaces, n, in the parking lot that could be placed perpendicular to a curb that is 135 feet long, based on the standard width of a parking space. Which of the following describes all the possible values of n ?",
choices: [
{ label: "A", text: "<strong>18 ≤ n, which ≤ 135</strong>" },
{ label: "B", text: "<strong>7 . 5 ≤ n, which ≤ 9</strong>" },
{ label: "C", text: "<strong>15 ≤ n, which ≤ 135</strong>" },
{ label: "D", text: "<strong>15 ≤ n, which ≤ 18</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Placing the parking spaces with the minimum width of 7.5 feet gives the maximum possible number of parking spaces. Thus, the maximum number that can be placed perpendicular to a 135-foot-long curb is <strong>135 over 7 . 5 = 18</strong>. Placing the parking spaces with the maximum width of 9 feet gives the minimum number of parking spaces. Thus, the minimum number that can be placed perpendicular to a 135-foot-long curb is <strong>135 over 9 = 15</strong>. Therefore, if n is the number of parking spaces in the lot, the range of possible values for n is <strong>15 ≤ n, which ≤ 18</strong>.Choices A and C are incorrect. These choices equate the length of the curb with the maximum possible number of parking spaces. Choice B is incorrect. This is the range of possible values for the width of a parking space instead of the range of possible values for the number of parking spaces.",
hasFigure: false,
},
{
id: "74c98c82",
type: "spr",
questionHtml:
"An event planner is planning a party. It costs the event planner a onetime fee of <strong>dollar sign 35</strong> to rent the venue and <strong>dollar sign 10.25</strong> per attendee. The event planner has a budget of <strong>dollar sign 200</strong>. What is the greatest number of attendees possible without exceeding the budget?",
choices: [],
correctAnswer: "16",
explanation:
"The correct answer is <strong>16</strong>. The total cost of the party is found by adding the onetime fee of the venue to the cost per attendee times the number of attendees. Let <strong>x</strong> be the number of attendees. The expression <strong>35 + 10.25 x</strong> thus represents the total cost of the party. It's given that the budget is <strong>dollar sign 200</strong>, so this situation can be represented by the inequality <strong>35 + 10.25 x < or = 200</strong>. The greatest number of attendees can be found by solving this inequality for <strong>x</strong>. Subtracting <strong>35</strong> from both sides of this inequality gives <strong>10.25 x < or = 165</strong>. Dividing both sides of this inequality by <strong>10.25</strong> results in approximately <strong>x < or = 16.098</strong>. Since the question is stated in terms of attendees, rounding <strong>x</strong> down to the nearest whole number, <strong>16</strong>, gives the greatest number of attendees possible.",
hasFigure: false,
},
{
id: "80da233d",
type: "mcq",
questionHtml:
"A certain elephant weighs 200 pounds at birth and gains more than 2 but less than 3 pounds per day during its first year. Which of the following inequalities represents all possible weights w, in pounds, for the elephant 365 days after birth?",
choices: [
{ label: "A", text: "<strong>400 < w, which < 600</strong>" },
{ label: "B", text: "<strong>565 < w, which < 930</strong>" },
{ label: "C", text: "<strong>730 < w, which < 1, 095</strong>" },
{ label: "D", text: "<strong>930 < w, which < 1, 295</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Its given that the elephant weighs 200 pounds at birth and gains more than 2 pounds but less than 3 pounds per day during its first year. The inequality <strong>200 + 2 d < w, which < 200 + 3 d</strong> represents this situation, where d is the number of days after birth. Substituting 365 for d in the inequality gives <strong>200 + 2 · 365 < w, which < 200 + 3 · 365</strong>, or <strong>930 < w, which < 1, 295</strong>.Choice A is incorrect and may result from solving the inequality <strong>200 · 2 < w, which < 200 · 3</strong>. Choice B is incorrect and may result from solving the inequality for a weight range of more than 1 pound but less than 2 pounds: <strong>200 + 1 · 365 < w, which < 200 + 2 · 365</strong>. Choice C is incorrect and may result from calculating the possible weight gained by the elephant during the first year without adding the 200 pounds the elephant weighed at birth.",
hasFigure: false,
},
{
id: "8f0c82e2",
type: "mcq",
questionHtml:
"The minimum value of <strong>x</strong> is <strong>12</strong> less than <strong>6</strong> times another number <strong>n</strong>. Which inequality shows the possible values of <strong>x</strong>?",
choices: [
{ label: "A", text: "<strong>x < or = 6 n 12</strong>" },
{ label: "B", text: "<strong>x > or = 6 n 12</strong>" },
{ label: "C", text: "<strong>x < or = 12 6 n</strong>" },
{ label: "D", text: "<strong>x > or = 12 6 n</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that the minimum value of <strong>x</strong> is <strong>12</strong> less than <strong>6</strong> times another number <strong>n</strong>. Therefore, the possible values of <strong>x</strong> are all greater than or equal to the value of <strong>12</strong> less than <strong>6</strong> times <strong>n</strong>. The value of <strong>6</strong> times <strong>n</strong> is given by the expression <strong>6 n</strong>. The value of <strong>12</strong> less than <strong>6 n</strong> is given by the expression <strong>6 n 12</strong>. Therefore, the possible values of <strong>x</strong> are all greater than or equal to <strong>6 n 12</strong>. This can be shown by the inequality <strong>x > or = 6 n 12</strong>.<br>Choice A is incorrect. This inequality shows the possible values of <strong>x</strong> if the maximum, not the minimum, value of <strong>x</strong> is <strong>12</strong> less than <strong>6</strong> times <strong>n</strong>.<br>Choice C is incorrect. This inequality shows the possible values of <strong>x</strong> if the maximum, not the minimum, value of <strong>x</strong> is <strong>6</strong> times <strong>n</strong> less than <strong>12</strong>, not <strong>12</strong> less than <strong>6</strong> times <strong>n</strong>.<br>Choice D is incorrect. This inequality shows the possible values of <strong>x</strong> if the minimum value of <strong>x</strong> is <strong>6</strong> times <strong>n</strong> less than <strong>12</strong>, not <strong>12</strong> less than <strong>6</strong> times <strong>n</strong>.",
hasFigure: false,
},
{
id: "90bd9ef8",
type: "mcq",
questionHtml:
"The average annual energy cost for a certain home is $4,334. The homeowner plans to spend $25,000 to install a geothermal heating system. The homeowner estimates that the average annual energy cost will then be $2,712. Which of the following inequalities can be solved to find t, the number of years after installation at which the total amount of energy cost savings will exceed the installation cost?",
choices: [
{
label: "A",
text: "<strong>25, 000 > (4, 334 2, 712, ) · t</strong>",
},
{
label: "B",
text: "<strong>25, 000 < (4, 334 2, 712, ) · t</strong>",
},
{ label: "C", text: "<strong>25, 000 4, 334 > 2, 712 t</strong>" },
{
label: "D",
text: "<strong>25, 000 > the fraction with numerator 4, 332, and denominator 2, 712, end fraction, t</strong>",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. The savings each year from installing the geothermal heating system will be the average annual energy cost for the home before the geothermal heating system installation minus the average annual energy cost after the geothermal heating system installation, which is <strong>4, 334 2, 712</strong> dollars. In t years, the savings will be <strong>(4, 334 2, 712, ) · t</strong> dollars. Therefore, the inequality that can be solved to find the number of years after installation at which the total amount of energy cost savings will exceed (be greater than) the installation cost, $25,000, is <strong>25, 000 < (4, 334 2, 712, ) · t</strong>.Choice A is incorrect. It gives the number of years after installation at which the total amount of energy cost savings will be less than the installation cost. Choice C is incorrect and may result from subtracting the average annual energy cost for the home from the onetime cost<br><br>of the geothermal heating system installation. To find the predicted total savings, the predicted average cost should be subtracted from the average annual energy cost before the installation, and the result should be multiplied by the number of years, t. Choice D is incorrect and may result from misunderstanding the context. The ratio <strong>4, 332 over 2, 712</strong> compares the average energy cost before installation and the average energy cost after installation; it does not represent the savings.",
hasFigure: false,
},
{
id: "948087f2",
type: "mcq",
questionHtml:
"Which of the following ordered pairs (x, y) satisfies the system of inequalities above?",
choices: [
{ label: "A", text: "<strong>2 1</strong>" },
{ label: "B", text: "<strong>1, 3</strong>" },
{ label: "C", text: "<strong>1, 5</strong>" },
{ label: "D", text: "<strong>2 1</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Any point (x, y) that is a solution to the given system of inequalities must satisfy both inequalities in the system. The second inequality in the system can be rewritten as <strong>x > y + 1</strong>. Of the given answer choices, only choice D satisfies this inequality, because inequality <strong>2 > 1 + 1</strong> is a true statement. The point <strong>with coordinates 2 1</strong> also satisfies the first inequality.Alternate approach: Substituting <strong>the ordered pair 2 1</strong> into the first inequality gives <strong>1 ≤ 3 · 2 + 1</strong>, or <strong>1 ≤ 7</strong>, which is a true statement. Substituting <strong>the ordered pair 2 1</strong> into the second inequality gives <strong>2 1 > 1</strong>, or <strong>3 > 1</strong>, which is a true statement. Therefore, since <strong>the ordered pair 2 1</strong> satisfies both inequalities, it is a solution to the system.<br>Choice A is incorrect because substituting 2 for x and 1 for y in the first inequality gives <strong>1 ≤ 3 · 2 + 1</strong>, or <strong>1 ≤ 5</strong>, which is false. Choice B is incorrect because substituting 1 for x and 3 for y in the first inequality gives <strong>3 ≤ 3 · 1 + 1</strong>, or <strong>3 ≤ 2</strong>, which is false. Choice C is incorrect because substituting 1 for x and 5 for y in the first inequality gives <strong>5 ≤ 3 · 1 + 1</strong>, or <strong>5 ≤ 4</strong>, which is false.",
hasFigure: false,
},
{
id: "968e9e51",
type: "mcq",
questionHtml:
"Which of the following ordered pairs <strong>x, y</strong> is a solution to the system of inequalities above?",
choices: [
{ label: "A", text: "<strong>1, 0</strong>" },
{ label: "B", text: "<strong>1, 0</strong>" },
{ label: "C", text: "<strong>0, 1</strong>" },
{ label: "D", text: "<strong>0 1</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The solutions to the given system of inequalities is the set of all ordered pairs <strong>x, y</strong> that satisfy both inequalities in the system. For an ordered pair to satisfy the inequality <strong>y ≤ x</strong>, the value of the ordered pairs y-coordinate must be less than or equal to the value of the ordered pairs x-coordinate. This is true of the ordered pair <strong>0 1</strong>, because <strong>1 ≤ 0</strong>. To satisfy the inequality <strong>y ≤ x</strong>, the value of the ordered pairs y-coordinate must be less than or equal to the value of the additive inverse of the ordered pairs x-coordinate. This is also true of the ordered pair <strong>0 1</strong>. Because 0 is its own additive inverse, <strong>1 ≤ the of 0</strong> is the same as <strong>1 ≤ 0</strong>. Therefore, the ordered pair <strong>0 1</strong> is a solution to the given system of inequalities.Choice A is incorrect. This ordered pair satisfies only the inequality <strong>y ≤ x</strong> in the given system, not both inequalities. Choice B incorrect. This ordered pair satisfies only the inequality <strong>y ≤ x</strong> in the system, but not both inequalities. Choice C is incorrect. This ordered pair satisfies neither inequality.",
hasFigure: false,
},
{
id: "b1228811",
type: "mcq",
questionHtml:
"Marisa needs to hire at least 10 staff members for an upcoming project. The staff members will be made up of junior directors, who will be paid $640 per week, and senior directors, who will be paid $880 per week. Her budget for paying the staff members is no more than $9,700 per week. She must hire at least 3 junior directors and at least 1 senior director. Which of the following systems of inequalities represents the conditions described if x is the number of junior directors and y is the number of senior directors?",
choices: [
{
label: "A",
text: "<strong>640 x + 880 y ≥ 9, 700; x + y ≤ 10; x ≥ 3; y ≥ 1</strong>",
},
{
label: "B",
text: "<strong>640 x + 880 y ≤ 9, 700; x + y ≥ 10; x ≥ 3; y ≥ 1</strong>",
},
{
label: "C",
text: "<strong>640 x + 880 y ≥ 9, 700; x + y ≥ 10; x ≤ 3; y ≤ 1</strong>",
},
{
label: "D",
text: "<strong>640 x + 880 y ≤ 9, 700; x + y ≤ 10; x ≤ 3; y ≤ 1</strong>",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. Marisa will hire x junior directors and y senior directors. Since she needs to hire at least 10 staff members, <strong>x + y ≥ 10</strong>. Each junior director will be paid $640 per week, and each senior director will be paid $880 per week. Marisas budget for paying the new staff is no more than $9,700 per week; in terms of x and y, this condition is <strong>640 x + 880 y ≤ 9, 700</strong>. Since Marisa must hire at least 3 junior directors and at least 1 senior director, it follows that <strong>x ≥ 3</strong> and <strong>y ≥ 1</strong>. All four of these conditions are represented correctly in choice B.Choices A and C are incorrect. For example, the first condition, <strong>640 x + 880 y ≥ 9, 700</strong>, in each of these options implies that Marisa can pay the new staff members more than her budget of $9,700. Choice D is incorrect because Marisa needs to hire at least 10 staff members, not at most 10 staff members, as the inequality <strong>x + y ≤ 10</strong> implies.",
hasFigure: false,
},
{
id: "b31c3117",
type: "mcq",
questionHtml:
"The Karvonen formula above shows the relationship between Alices target heart rate H, in beats per minute (bpm), and the intensity level p of different activities. When <strong>p = 0</strong>, Alice has a resting heart rate. When <strong>p = 1</strong>, Alice has her maximum heart rate. It is recommended that p be between 0.5 and 0.85 for Alice when she trains. Which of the following inequalities describes Alices target training heart rate?",
choices: [
{ label: "A", text: "<strong>120 ≤ H, which ≤ 162</strong>" },
{ label: "B", text: "<strong>102 ≤ H, which ≤ 120</strong>" },
{ label: "C", text: "<strong>60 ≤ H, which ≤ 162</strong>" },
{ label: "D", text: "<strong>60 ≤ H, which ≤ 102</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. When Alice trains, its recommended that p be between 0.5 and 0.85. Therefore, her target training heart rate is represented by the values of H corresponding to <strong>0 . 5 ≤ p, which ≤ 0 . 8 5</strong>. When <strong>p = 0 . 5</strong>, <strong>H = 120 · 0 . 5 + 60</strong>, or <strong>H = 120</strong>. When <strong>p = 0 . 8 5</strong>, <strong>H = 120 · 0 . 8 5 + 60</strong>, or <strong>H = 162</strong>. Therefore, the inequality that describes Alices target training heart rate is <strong>120 ≤ H, which ≤ 162</strong>.Choice B is incorrect. This inequality describes Alices target heart rate for <strong>0 . 3 5 ≤ p, which ≤ 0 . 5</strong>. Choice C is incorrect. This inequality describes her target heart rate for <strong>0 ≤ p, which ≤ 0 . 8 5</strong>. Choice D is incorrect. This inequality describes  her target heart rate for <strong>0 ≤ p, which ≤ 0 . 3 5</strong>.",
hasFigure: false,
},
{
id: "bf5f80c6",
type: "mcq",
questionHtml:
"<em>(expression)</em><br>Which point (<em>(expression)</em>, <em>(expression)</em>) is a solution to the given inequality in the <em>(expression)</em>-plane?",
choices: [
{ label: "A", text: "(<em>(expression)</em>, <em>(expression)</em>)" },
{ label: "B", text: "(<em>(expression)</em>, <em>(expression)</em>)" },
{ label: "C", text: "(<em>(expression)</em>, <em>(expression)</em>)" },
{ label: "D", text: "(<em>(expression)</em>, <em>(expression)</em>)" },
],
correctAnswer: "A",
explanation:
"Choice D is correct. For a point <strong>(x, y)</strong> to be a solution to the given inequality in the xy-plane, the value of the points y-coordinate must be less than the value of <strong> 4 x + 4</strong>, where <strong>x</strong> is the value of the x-coordinate of the point. This is true of the point <strong>(4, 0)</strong> because <strong>0 < 4 (4) + 4</strong>, or <strong>0 < 20</strong>. Therefore, the point <strong>(4, 0)</strong> is a solution to the given inequality.<br><br>Choices A, B, and C are incorrect. None of these points are a solution to the given inequality because each points y-coordinate is greater than the value of <strong> 4 x + 4</strong> for the points x-coordinate.",
hasFigure: false,
},
{
id: "c17d9ba9",
type: "spr",
questionHtml:
"A number <strong>x</strong> is at most <strong>17</strong> less than <strong>5</strong> times the value of <strong>y</strong>. If the value of <strong>y</strong> is <strong>3</strong>, what is the greatest possible value of <strong>x</strong>?",
choices: [],
correctAnswer: "-2",
explanation:
"The correct answer is <strong>2</strong>. It's given that a number <strong>x</strong> is at most <strong>17</strong> less than <strong>5</strong> times the value of <strong>y</strong>, or <strong>x < or = 5 y 17</strong>. Substituting <strong>3</strong> for <strong>y</strong> in this inequality yields <strong>x < or = 5 (3) 17</strong>, or <strong>x < or = 2</strong>. Thus, if the value of <strong>y</strong> is <strong>3</strong>, the greatest possible value of <strong>x</strong> is <strong>2</strong>.",
hasFigure: false,
},
{
id: "d02193fb",
type: "mcq",
questionHtml:
"The boundary of the inequality is a dashed line.<br><br>The line slants sharply down from left to right.<br>The line passes through the following points:<br><br>(negative 1 comma 5)<br>(0 comma 1)<br>(1 comma negative 3)<br><br>The area above and to the right of the boundary is shaded.<br><br>The shaded region shown represents the solutions to which inequality?",
choices: [
{ label: "A", text: "<strong>y < 1 + 4 x</strong>" },
{ label: "B", text: "<strong>y < 1 4 x</strong>" },
{ label: "C", text: "<strong>y > 1 + 4 x</strong>" },
{ label: "D", text: "<strong>y > 1 4 x</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The equation for the line representing the boundary of the shaded region can be written in slope-intercept form <strong>y = b + m x</strong>, where <strong>m</strong> is the slope and <strong>(0, b)</strong> is the y-intercept of the line. For the graph shown, the boundary line passes through the points <strong>(0, 1)</strong> and <strong>(1 3)</strong>. Given two points on a line, <strong>(x 1, y 1)</strong> and <strong>(x 2, y 2)</strong>, the slope of the line can be calculated using the equation <strong>m = (y 2 y 1) / (x 2 x 1)</strong>. Substituting the points <strong>(0, 1)</strong> and <strong>(1 3)</strong> for <strong>(x 1, y 1)</strong> and <strong>(x 2, y 2)</strong> in this equation yields <strong>m = (3 1) / (1 0)</strong>, which is equivalent to <strong>m = (4) / (1)</strong>, or <strong>m = 4</strong>. Since the point <strong>(0, 1)</strong> represents the y-intercept, it follows that <strong>b = 1</strong>. Substituting <strong>4</strong> for <strong>m</strong> and <strong>1</strong> for <strong>b</strong> in the equation <strong>y = b + m x</strong> yields <strong>y = 1 4 x</strong> as the equation of the boundary line. Since the shaded region represents all the points above this boundary line, it follows that the shaded region shown represents the solutions to the inequality <strong>y > 1 4 x</strong>.<br>Choice A is incorrect. This inequality represents a region below, not above, a boundary line with a slope of <strong>4</strong>, not <strong>4</strong>.<br>Choice B is incorrect. This inequality represents a region below, not above, the boundary line shown.<br>Choice C is incorrect. This inequality represents a region whose boundary line has a slope of <strong>4</strong>, not <strong>4</strong>.",
hasFigure: true,
figureUrl: "/practice-images/d02193fb_svg1.svg",
},
{
id: "e9ef0e6b",
type: "mcq",
questionHtml:
"A model estimates that whales from the genus Eschrichtius travel <strong>72</strong> to <strong>77</strong> miles in the ocean each day during their migration. Based on this model, which inequality represents the estimated total number of miles, <strong>x</strong>, a whale from the genus Eschrichtius could travel in <strong>16</strong> days of its migration?",
choices: [
{ label: "A", text: "<strong>72 + 16 < or = x < or = 77 + 16</strong>" },
{
label: "B",
text: "<strong>(72) (16) < or = x < or = (77) (16)</strong>",
},
{ label: "C", text: "<strong>72 < or = 16 + x < or = 77</strong>" },
{ label: "D", text: "<strong>72 < or = 16 x < or = 77</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. It's given that the model estimates that whales from the genus Eschrichtius travel <strong>72</strong> to <strong>77</strong> miles in the ocean each day during their migration. If one of these whales travels <strong>72</strong> miles each day for <strong>16</strong> days, then the whale travels <strong>72 (16)</strong> miles total. If one of these whales travels <strong>77</strong> miles each day for <strong>16</strong> days, then the whale travels <strong>77 (16)</strong> miles total. Therefore, the model estimates that in <strong>16</strong> days of its migration, a whale from the genus Eschrichtius could travel at least <strong>72 (16)</strong> and at most <strong>77 (16)</strong> miles total. Thus, the inequality <strong>(72) (16) < or = x < or = (77) (16)</strong> represents the estimated total number of miles, <strong>x</strong>, a whale from the genus Eschrichtius could travel in <strong>16</strong> days of its migration.<br>Choice A is incorrect and may result from conceptual errors.<br>Choice C is incorrect and may result from conceptual errors.<br>Choice D is incorrect and may result from conceptual errors.",
hasFigure: false,
},
{
id: "f02b4509",
type: "mcq",
questionHtml:
"A moving truck can tow a trailer if the combined weight of the trailer and the boxes it contains is no more than <strong>4, 600</strong> pounds. What is the maximum number of boxes this truck can tow in a trailer with a weight of <strong>500</strong> pounds if each box weighs <strong>120</strong> pounds?",
choices: [
{ label: "A", text: "<strong>34</strong>" },
{ label: "B", text: "<strong>35</strong>" },
{ label: "C", text: "<strong>38</strong>" },
{ label: "D", text: "<strong>39</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that the truck can tow a trailer if the combined weight of the trailer and the boxes it contains is no more than <strong>4, 600</strong> pounds. If the trailer has a weight of <strong>500</strong> pounds and each box weighs <strong>120</strong> pounds, the expression <strong>500 + 120 b</strong>, where <strong>b</strong> is the number of boxes, gives the combined weight of the trailer and the boxes. Since the combined weight must be no more than <strong>4, 600</strong> pounds, the possible numbers of boxes the truck can tow are given by the inequality <strong>500 + 120 b < or = 4, 600</strong>. Subtracting <strong>500</strong> from both sides of this inequality yields <strong>120 b < or = 4, 100</strong>. Dividing both sides of this inequality by <strong>120</strong> yields <strong>b < or = (205) / (6)</strong>, or <strong>b</strong> is less than or equal to approximately <strong>34.17</strong>. Since the number of boxes, <strong>b</strong>, must be a whole number, the maximum number of boxes the truck can tow is the greatest whole number less than <strong>34.17</strong>, which is <strong>34</strong>.<br>Choice B is incorrect. Towing the trailer and <strong>35</strong> boxes would yield a combined weight of <strong>4, 700</strong> pounds, which is greater than <strong>4, 600</strong> pounds.<br>Choice C is incorrect. Towing the trailer and <strong>38</strong> boxes would yield a combined weight of <strong>5, 060</strong> pounds, which is greater than <strong>4, 600</strong> pounds.<br>Choice D is incorrect. Towing the trailer and <strong>39</strong> boxes would yield a combined weight of <strong>5, 180</strong> pounds, which is greater than <strong>4, 600</strong> pounds.",
hasFigure: false,
},
{
id: "f224df07",
type: "mcq",
questionHtml:
"A cargo helicopter delivers only 100-pound packages and 120-pound packages. For each delivery trip, the helicopter must carry at least 10 packages, and the total weight of the packages can be at most 1,100 pounds. What is the maximum number of 120-pound packages that the helicopter can carry per trip?",
choices: [
{ label: "A", text: "2" },
{ label: "B", text: "4" },
{ label: "C", text: "5" },
{ label: "D", text: "6" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Let a equal the number of 120-pound packages, and let b equal the number of 100-pound packages. Its given that the total weight of the packages can be at most 1,100 pounds: the inequality <strong>120 a + 100 b ≤ 1, 100</strong> represents this situation. Its also given that the helicopter must carry at least 10 packages: the inequality <strong>a + b ≥ 10</strong> represents this situation. Values of a and b that satisfy these two inequalities represent the allowable numbers of 120-pound packages and 100-pound packages the helicopter can transport. To maximize the number of 120-pound packages, a, in the helicopter, the number of 100-pound packages, b, in the helicopter needs to be minimized. Expressing b in terms of a in the second inequality yields <strong>b ≥ 10 a</strong>, so the minimum value of b is equal to <strong>10 a</strong>. Substituting <strong>10 a</strong> for b in the first inequality results in <strong>120 a + 100 · (10 a, ) ≤ 1, 100</strong>. Using the distributive property to rewrite this inequality yields <strong>120 a + 1, 000 100 a ≤ 1, 100</strong>, or <strong>20 a + 1, 000 ≤ 1, 100</strong>. Subtracting 1,000 from both sides of this inequality yields <strong>20 a ≤ 100</strong>. Dividing both sides of this inequality by 20 results in <strong>a ≤ 5</strong>. This means that the maximum number of 120-pound packages that the helicopter can carry per trip is 5.Choices A, B, and D are incorrect and may result from incorrectly creating or solving the system of inequalities.",
hasFigure: false,
},
{
id: "f2bbd43d",
type: "mcq",
questionHtml:
"<strong>y > 14</strong><br><strong>4 x + y < 18</strong><br>The point <strong>(x, 53)</strong> is a solution to the system of inequalities in the xy-plane. Which of the following could be the value of <strong>x</strong>?",
choices: [
{ label: "A", text: "<strong>9</strong>" },
{ label: "B", text: "<strong>5</strong>" },
{ label: "C", text: "<strong>5</strong>" },
{ label: "D", text: "<strong>9</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that the point <strong>(x, 53)</strong> is a solution to the given system of inequalities in the xy-plane. This means that the coordinates of the point, when substituted for the variables <strong>x</strong> and <strong>y</strong>, make both of the inequalities in the system true. Substituting <strong>53</strong> for <strong>y</strong> in the inequality <strong>y > 14</strong> yields <strong>53 > 14</strong>, which is true. Substituting <strong>53</strong> for <strong>y</strong> in the inequality <strong>4 x + y < 18</strong> yields <strong>4 x + 53 < 18</strong>. Subtracting <strong>53</strong> from both sides of this inequality yields <strong>4 x < 35</strong>. Dividing both sides of this inequality by <strong>4</strong> yields <strong>x < 8.75</strong>. Therefore, <strong>x</strong> must be a value less than <strong>8.75</strong>. Of the given choices, only <strong>9</strong> is less than <strong>8.75</strong>.<br>Choice B is incorrect. Substituting <strong>5</strong> for <strong>x</strong> and <strong>53</strong> for <strong>y</strong> in the inequality <strong>4 x + y < 18</strong> yields <strong>4 (5) + 53 < 18</strong>, or <strong>33 < 18</strong>, which is not true.<br>Choice C is incorrect. Substituting <strong>5</strong> for <strong>x</strong> and <strong>53</strong> for <strong>y</strong> in the inequality <strong>4 x + y < 18</strong> yields <strong>4 (5) + 53 < 18</strong>, or <strong>73 < 18</strong>, which is not true.<br>Choice D is incorrect. Substituting <strong>9</strong> for <strong>x</strong> and <strong>53</strong> for <strong>y</strong> in the inequality <strong>4 x + y < 18</strong> yields <strong>4 (9) + 53 < 18</strong>, or <strong>89 < 18</strong>, which is not true.",
hasFigure: false,
},
];
export const LINEAR_INEQ_HARD: PracticeQuestion[] = [
{
id: "03503d49",
type: "mcq",
questionHtml:
"A business owner plans to purchase the same model of chair for each of the <strong>81</strong> employees. The total budget to spend on these chairs is <strong>dollar sign 14, 000</strong>, which includes a <strong>7 % sign</strong> sales tax. Which of the following is closest to the maximum possible price per chair, before sales tax, the business owner could pay based on this budget?",
choices: [
{ label: "A", text: "<strong>dollar sign 148.15</strong>" },
{ label: "B", text: "<strong>dollar sign 161.53</strong>" },
{ label: "C", text: "<strong>dollar sign 172.84</strong>" },
{ label: "D", text: "<strong>dollar sign 184.94</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that a business owner plans to purchase <strong>81</strong> chairs. If <strong>p</strong> is the price per chair, the total price of purchasing <strong>81</strong> chairs is <strong>81 p</strong>. Its also given that <strong>7 % sign</strong> sales tax is included, which is equivalent to <strong>81 p</strong> multiplied by <strong>1.07</strong>, or <strong>81 (1.07) p</strong>. Since the total budget is <strong>dollar sign 14, 000</strong>, the inequality representing the situation is given by <strong>81 (1.07) p < or = 14, 000</strong>. Dividing both sides of this inequality by <strong>81 (1.07)</strong> and rounding the result to two decimal places gives  <strong>p < or = 161.53</strong>. To not exceed the budget, the maximum possible price per chair is <strong>dollar sign 161.53</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect. This is the maximum possible price per chair including sales tax, not the maximum possible price per chair before sales tax.<br>Choice D is incorrect. This is the maximum possible price if the sales tax is added to the total budget, not the maximum possible price per chair before sales tax.",
hasFigure: false,
},
{
id: "1035faea",
type: "mcq",
questionHtml:
"A psychologist set up an experiment to study the tendency of a person to select the first item when presented with a series of items. In the experiment, 300 people were presented with a set of five pictures arranged in random order. Each person was asked to choose the most appealing picture. Of the first 150 participants, 36 chose the first picture in the set. Among the remaining 150 participants, p people chose the first picture in the set. If more than 20% of all participants chose the first picture in the set, which of the following inequalities best describes the possible values of p ?",
choices: [
{
label: "A",
text: "<strong>p > 0 . 20 · (300 36, )</strong>, where <strong>p ≤ 150</strong>",
},
{
label: "B",
text: "<strong>p > 0 . 20 · (300 + 36, )</strong>, where <strong>p ≤ 150</strong>",
},
{
label: "C",
text: "<strong>p 36 > 0 . 20 · 300</strong>, where <strong>p ≤ 150</strong>",
},
{
label: "D",
text: "<strong>p + 36 > 0 . 20 · 300</strong>, where <strong>p ≤ 150</strong>",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. Of the first 150 participants, 36 chose the first picture in the set, and of the 150 remaining participants, p chose the first picture in the set. Hence, the proportion of the participants who chose the first picture in the set is <strong>the fraction with numerator 36 + p, and denominator 300</strong>. Since more than 20% of all the participants chose the first picture, it follows that <strong>the fraction with numerator 36 + p, and denominator 300 > 0 . 2 0</strong>.This inequality can be rewritten as <strong>p + 36 > 0 . 2 0 · 300</strong>. Since p is a number of people among the remaining 150 participants, <strong>p ≤ 150</strong>.<br>Choices A, B, and C are incorrect and may be the result of some incorrect interpretations of the given information or of computational errors.",
hasFigure: false,
},
{
id: "1a621af4",
type: "spr",
questionHtml:
"A number <strong>x</strong> is at most <strong>2</strong> less than <strong>3</strong> times the value of <strong>y</strong>. If the value of <strong>y</strong> is <strong>4</strong>, what is the greatest possible value of <strong>x</strong>?",
choices: [],
correctAnswer: "-14",
explanation:
"The correct answer is <strong>14</strong>. It's given that a number <strong>x</strong> is at most <strong>2</strong> less than <strong>3</strong> times the value of <strong>y</strong>. Therefore, <strong>x</strong> is less than or equal to <strong>2</strong> less than <strong>3</strong> times the value of <strong>y</strong>. The expression <strong>3 y</strong> represents <strong>3</strong> times the value of <strong>y</strong>. The expression <strong>3 y 2</strong> represents <strong>2</strong> less than <strong>3</strong> times the value of <strong>y</strong>. Therefore, <strong>x</strong> is less than or equal to <strong>3 y 2</strong>. This can be shown by the inequality <strong>x < or = 3 y 2</strong>. Substituting <strong>4</strong> for <strong>y</strong> in this inequality yields <strong>x < or = 3 (4) 2</strong> or, <strong>x < or = 14</strong>. Therefore, if the value of <strong>y</strong> is <strong>4</strong>, the greatest possible value of <strong>x</strong> is <strong>14</strong>.",
hasFigure: false,
},
{
id: "45cfb9de",
type: "mcq",
questionHtml:
"Adams school is a 20-minute walk or a 5-minute bus ride away from his house. The bus runs once every 30 minutes, and the number of minutes, w, that Adam waits for the bus varies between 0 and 30. Which of the following inequalities gives the values of w for which it would be faster for Adam to walk to school?",
choices: [
{ label: "A", text: "<strong>w 5 < 20</strong>" },
{ label: "B", text: "<strong>w 5 > 20</strong>" },
{ label: "C", text: "<strong>w + 5 < 20</strong>" },
{ label: "D", text: "<strong>w + 5 > 20</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. It is given that w is the number of minutes that Adam waits for the bus. The total time it takes Adam to get to school on a day he takes the bus is the sum of the minutes, w, he waits for the bus and the 5 minutes the bus ride takes; thus, this time, in minutes, is w + 5. It is also given that the total amount of time it takes Adam to get to school on a day that he walks is 20 minutes. Therefore, w + 5 > 20 gives the values of w for which it would be faster for Adam to walk to school.Choices A and B are incorrect because w 5 is not the total length of time for Adam to wait for and then take the bus to school. Choice C is incorrect because the inequality should be true when walking 20 minutes is faster than the time it takes Adam to wait for and ride the bus, not less.",
hasFigure: false,
},
{
id: "48fb34c8",
type: "mcq",
questionHtml:
"<strong>y > 13 x 18</strong><br>For which of the following tables are all the values of <strong>x</strong> and their corresponding values of <strong>y</strong> solutions to the given inequality?",
choices: [
{
label: "A",
text: "<strong>x</strong><br><strong>y</strong><br><br><strong>3</strong><br><strong>21</strong><br><br><strong>5</strong><br><strong>47</strong><br><br><strong>8</strong><br><strong>86</strong>",
},
{
label: "B",
text: "<strong>x</strong><br><strong>y</strong><br><br><strong>3</strong><br><strong>26</strong><br><br><strong>5</strong><br><strong>42</strong><br><br><strong>8</strong><br><strong>86</strong>",
},
{
label: "C",
text: "<strong>x</strong><br><strong>y</strong><br><br><strong>3</strong><br><strong>16</strong><br><br><strong>5</strong><br><strong>42</strong><br><br><strong>8</strong><br><strong>81</strong>",
},
{
label: "D",
text: "<strong>x</strong><br><strong>y</strong><br><br><strong>3</strong><br><strong>26</strong><br><br><strong>5</strong><br><strong>52</strong><br><br><strong>8</strong><br><strong>91</strong>",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. All the tables in the choices have the same three values of <strong>x</strong>, so each of the three values of <strong>x</strong> can be substituted in the given inequality to compare the corresponding values of <strong>y</strong> in each of the tables. Substituting <strong>3</strong> for <strong>x</strong> in the given inequality yields <strong>y > 13 (3) 18</strong>, or <strong>y > 21</strong>. Therefore, when <strong>x = 3</strong>, the corresponding value of <strong>y</strong> is greater than <strong>21</strong>. Substituting <strong>5</strong> for <strong>x</strong> in the given inequality yields <strong>y > 13 (5) 18</strong>, or <strong>y > 47</strong>. Therefore, when <strong>x = 5</strong>, the corresponding value of <strong>y</strong> is greater than <strong>47</strong>. Substituting <strong>8</strong> for <strong>x</strong> in the given inequality yields <strong>y > 13 (8) 18</strong>, or <strong>y > 86</strong>. Therefore, when <strong>x = 8</strong>, the corresponding value of <strong>y</strong> is greater than <strong>86</strong>. For the table in choice D, when <strong>x = 3</strong>, the corresponding value of <strong>y</strong> is <strong>26</strong>, which is greater than <strong>21</strong>; when <strong>x = 5</strong>, the corresponding value of <strong>y</strong> is <strong>52</strong>, which is greater than <strong>47</strong>; when <strong>x = 8</strong>, the corresponding value of <strong>y</strong> is <strong>91</strong>, which is greater than <strong>86</strong>. Therefore, the table in choice D gives values of <strong>x</strong> and their corresponding values of <strong>y</strong> that are all solutions to the given inequality.<br>Choice A is incorrect. In the table for choice A, when <strong>x = 3</strong>, the corresponding value of <strong>y</strong> is <strong>21</strong>, which is not greater than <strong>21</strong>; when <strong>x = 5</strong>, the corresponding value of <strong>y</strong> is <strong>47</strong>, which is not greater than <strong>47</strong>; when <strong>x = 8</strong>, the corresponding value of <strong>y</strong> is <strong>86</strong>, which is not greater than <strong>86</strong>.<br>Choice B is incorrect. In the table for choice B, when <strong>x = 5</strong>, the corresponding value of <strong>y</strong> is <strong>42</strong>, which is not greater than <strong>47</strong>; when <strong>x = 8</strong>, the corresponding value of <strong>y</strong> is <strong>86</strong>, which is not greater than <strong>86</strong>.<br>Choice C is incorrect. In the table for choice C, when <strong>x = 3</strong>, the corresponding value of <strong>y</strong> is <strong>16</strong>, which is not greater than <strong>21</strong>; when <strong>x = 5</strong>, the corresponding value of <strong>y</strong> is <strong>42</strong>, which is not greater than <strong>47</strong>; when <strong>x = 8</strong>, the corresponding value of <strong>y</strong> is <strong>81</strong>, which is not greater than <strong>86</strong>.",
hasFigure: false,
},
{
id: "541bef2f",
type: "mcq",
questionHtml:
"<strong>y < or = x + 7</strong><br><strong>y > or = 2 x 1</strong><br>Which point <strong>(x, y)</strong> is a solution to the given system of inequalities in the xy-plane?",
choices: [
{ label: "A", text: "<strong>(14, 0)</strong>" },
{ label: "B", text: "<strong>(0 14)</strong>" },
{ label: "C", text: "<strong>(0, 14)</strong>" },
{ label: "D", text: "<strong>(14, 0)</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. A point <strong>(x, y)</strong> is a solution to a system of inequalities in the xy-plane if substituting the x-coordinate and the y-coordinate of the point for <strong>x</strong> and <strong>y</strong>, respectively, in each inequality makes both of the inequalities true. Substituting the x-coordinate and the y-coordinate of choice D, <strong>14</strong> and <strong>0</strong>, for <strong>x</strong> and <strong>y</strong>, respectively, in the first inequality in the given system, <strong>y < or = x + 7</strong>, yields <strong>0 < or = 14 + 7</strong>, or <strong>0 < or = 21</strong>, which is true. Substituting <strong>14</strong> for <strong>x</strong> and <strong>0</strong> for <strong>y</strong> in the second inequality in the given system, <strong>y > or = 2 x 1</strong>, yields <strong>0 > or = 2 (14) 1</strong>, or <strong>0 > or = 29</strong>, which is true. Therefore, the point <strong>(14, 0)</strong> is a solution to the given system of inequalities in the xy-plane.<br>Choice A is incorrect. Substituting <strong>14</strong> for <strong>x</strong> and <strong>0</strong> for <strong>y</strong> in the inequality <strong>y < or = x + 7</strong> yields <strong>0 < or = 14 + 7</strong>, or <strong>0 < or = 7</strong>, which is not true.<br>Choice B is incorrect. Substituting <strong>0</strong> for <strong>x</strong> and <strong>14</strong> for <strong>y</strong> in the inequality <strong>y > or = 2 x 1</strong> yields <strong>14 > or = 2 (0) 1</strong>, or <strong>14 > or = 1</strong>, which is not true.<br>Choice C is incorrect. Substituting <strong>0</strong> for <strong>x</strong> and <strong>14</strong> for <strong>y</strong> in the inequality <strong>y < or = x + 7</strong> yields <strong>14 < or = 0 + 7</strong>, or <strong>14 < or = 7</strong>, which is not true.",
hasFigure: false,
},
{
id: "5bf5136d",
type: "mcq",
questionHtml:
"The triangle inequality theorem states that the sum of any two sides of a triangle must be greater than the length of the third side. If a triangle has side lengths of <strong>6</strong> and <strong>12</strong>, which inequality represents the possible lengths, <strong>x</strong>, of the third side of the triangle?",
choices: [
{ label: "A", text: "<strong>x < 18</strong>" },
{ label: "B", text: "<strong>x > 18</strong>" },
{ label: "C", text: "<strong>6 < x < 18</strong>" },
{ label: "D", text: "<strong>x < 6</strong> or <strong>x > 18</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that a triangle has side lengths of <strong>6</strong> and <strong>12</strong>, and <strong>x</strong> represents the length of the third side of the triangle. Its also given that the triangle inequality theorem states that the sum of any two sides of a triangle must be greater than the length of the third side. Therefore, the inequalities <strong>6 + x > 12</strong>, <strong>6 + 12 > x</strong>, and <strong>12 + x > 6</strong> represent all possible values of <strong>x</strong>. Subtracting <strong>6</strong> from both sides of the inequality <strong>6 + x > 12</strong> yields <strong>x > 12 6</strong>, or <strong>x > 6</strong>. Adding <strong>6</strong> and <strong>12</strong> in the inequality <strong>6 + 12 > x</strong> yields <strong>18 > x</strong>, or <strong>x < 18</strong>. Subtracting <strong>12</strong> from both sides of the inequality <strong>12 + x > 6</strong> yields <strong>x > 6 12</strong>, or <strong>x > 6</strong>. Since all x-values that satisfy the inequality <strong>x > 6</strong> also satisfy the inequality <strong>x > 6</strong>, it follows that the inequalities <strong>x > 6</strong> and <strong>x < 18</strong> represent the possible values of <strong>x</strong>. Therefore, the inequality <strong>6 < x < 18</strong> represents the possible lengths, <strong>x</strong>, of the third side of the triangle.<br>Choice A is incorrect. This inequality gives the upper bound for <strong>x</strong> but does not include its lower bound.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "6c71f3ec",
type: "mcq",
questionHtml:
"A salespersons total earnings consist of a base salary of <strong>x</strong> dollars per year, plus commission earnings of <strong>11 % sign</strong> of the total sales the salesperson makes during the year. This year, the salesperson has a goal for the total earnings to be at least <strong>3</strong> times and at most <strong>4</strong> times the base salary. Which of the following inequalities represents all possible values of total sales <strong>s</strong>, in dollars, the salesperson can make this year in order to meet that goal?",
choices: [
{ label: "A", text: "<strong>2 x < or = s < or = 3 x</strong>" },
{
label: "B",
text: "<strong>(2) / (0.11) x < or = s < or = (3) / (0.11) x</strong>",
},
{ label: "C", text: "<strong>3 x < or = s < or = 4 x</strong>" },
{
label: "D",
text: "<strong>(3) / (0.11) x < or = s < or = (4) / (0.11) x</strong>",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that a salesperson's total earnings consist of a base salary of <strong>x</strong> dollars per year plus commission earnings of <strong>11 % sign</strong> of the total sales the salesperson makes during the year. If the salesperson makes <strong>s</strong> dollars in total sales this year, the salespersons total earnings can be represented by the expression <strong>x + 0.11 s</strong>. Its also given that the salesperson has a goal for the total earnings to be at least <strong>3</strong> times and at most <strong>4</strong> times the base salary, which can be represented by the expressions <strong>3 x</strong> and <strong>4 x</strong>, respectively. Therefore, this situation can be represented by the inequality <strong>3 x < or = x + 0.11 s < or = 4 x</strong>. Subtracting <strong>x</strong> from each part of this inequality yields <strong>2 x < or = 0.11 s < or = 3 x</strong>. Dividing each part of this inequality by <strong>0.11</strong> yields <strong>(2) / (0.11) x < or = s < or = (3) / (0.11) x</strong>. Therefore, the inequality <strong>(2) / (0.11) x < or = s < or = (3) / (0.11) x</strong> represents all possible values of total sales <strong>s</strong>, in dollars, the salesperson can make this year in order to meet their goal.<br>Choice A is incorrect. This inequality represents a situation in which the total sales, rather than the total earnings, are at least <strong>2</strong> times and at most <strong>3</strong> times, rather than at least <strong>3</strong> times and at most <strong>4</strong> times, the base salary.<br>Choice C is incorrect. This inequality represents a situation in which the total sales, rather than the total earnings, are at least <strong>3</strong> times and at most <strong>4</strong> times the base salary.<br>Choice D is incorrect. This inequality represents a situation in which the total earnings are at least <strong>4</strong> times and at most <strong>5</strong> times, rather than at least <strong>3</strong> times and at most <strong>4</strong> times, the base salary.",
hasFigure: false,
},
{
id: "830120b0",
type: "mcq",
questionHtml:
"Which of the following consists of the y-coordinates of all the points that satisfy the system of inequalities above?",
choices: [
{ label: "A", text: "<strong>y > 6</strong>" },
{ label: "B", text: "<strong>y > 4</strong>" },
{ label: "C", text: "<strong>y > five-halves</strong>" },
{ label: "D", text: "<strong>y > three-halves</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Subtracting the same number from each side of an inequality gives an equivalent inequality. Hence, subtracting 1 from each side of the inequality <strong>2 x > 5</strong> gives <strong>2 x 1 > 4</strong>. So the given system of inequalities is equivalent to the system of inequalities <strong>y > 2 x 1</strong> and <strong>2 x 1 > 4</strong>, which can be rewritten as <strong>y > 2 x 1, which > 4</strong>. Using the transitive property of inequalities, it follows that <strong>y > 4</strong>.Choice A is incorrect because there are points with a y-coordinate less than 6 that satisfy the given system of inequalities. For example, <strong>3, 5 . 5</strong> satisfies both inequalities. Choice C is incorrect. This may result from solving the inequality <strong>2 x > 5</strong> for x, then replacing x with y. Choice D is incorrect because this inequality allows y-values that are not the y-coordinate of any point that satisfies both inequalities. For example, <strong>y = 2</strong> is contained in the set <strong>y > three halves</strong>; however, if 2 is substituted into the first inequality for y, the result is <strong>x < three halves</strong>. This cannot be true because the second inequality gives <strong>x > five halves</strong>.",
hasFigure: false,
},
{
id: "95cad55f",
type: "mcq",
questionHtml:
"A laundry service is buying detergent and fabric softener from its supplier. The supplier will deliver no more than 300 pounds in a shipment. Each container of detergent weighs 7.35  pounds, and each container of fabric softener weighs 6.2 pounds. The service wants to buy at least twice as many containers of detergent as containers of fabric softener. Let d represent the number of containers of detergent, and let s represent the number of containers of fabric softener, where d and s are nonnegative integers. Which of the following systems of inequalities best represents this situation?",
choices: [
{
label: "A",
text: "<strong>7 . three five d + 6 . 2 s ≤ 300, and, d ≥ 2 s</strong>",
},
{
label: "B",
text: "<strong>7 . three five d + 6 . 2 s ≤ 300, and, 2 d ≥ s</strong>",
},
{
label: "C",
text: "<strong>14 . 7 d + 6 . 2 s ≤ 300, and, d ≥ 2 s</strong>",
},
{
label: "D",
text: "<strong>14 . 7 d + 6 . 2 s ≤ 300, and, 2 d ≥ s</strong>",
},
],
correctAnswer: "A",
explanation:
"Choice A is correct. The number of containers in a shipment must have a weight less than or equal to 300 pounds. The total weight, in pounds, of detergent and fabric softener that the supplier delivers can be expressed as the weight of each container multiplied by the number of each type of container, which is 7.35d for detergent and 6.2s for fabric softener. Since this total cannot exceed 300 pounds, it follows that <strong>7 . 3 5 d + 6 . 2 s ≤ 300</strong>. Also, since the laundry service wants to buy at least twice as many containers of detergent as containers of fabric softener, the number of containers of detergent should be greater than or equal to two times the number of containers of fabric softener. This can be expressed by the inequality <strong>d ≥ 2 s</strong>.<br>Choice B is incorrect because it misrepresents the relationship between the numbers of each container that the laundry service wants to buy. Choice C is incorrect because the first inequality of the system incorrectly doubles the weight per container of detergent. The weight of each container of detergent is 7.35, not 14.7 pounds. Choice D is incorrect because it doubles the weight per container of detergent and transposes the relationship between the numbers of containers.",
hasFigure: false,
},
{
id: "963da34c",
type: "mcq",
questionHtml:
"A shipping service restricts the dimensions of the boxes it will ship for a certain type of service. The restriction states that for boxes shaped like rectangular prisms, the sum of the perimeter of the base of the box and the height of the box cannot exceed 130 inches. The perimeter of the base is determined using the width and length of the box. If a box has a height of 60 inches and its length is 2.5 times the width, which inequality shows the allowable width x, in inches, of the box?",
choices: [
{ label: "A", text: "<strong>zero < x, which ≤ 10</strong>" },
{
label: "B",
text: "<strong>zero < x, which ≤ 11 and two-thirds</strong>",
},
{
label: "C",
text: "<strong>zero < x, which ≤ 17 and one-half</strong>",
},
{ label: "D", text: "<strong>zero < x, which ≤ 20</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. If x is the width, in inches, of the box, then the length of the box is 2.5x inches. It follows that the perimeter of the base is <strong>2 · (2 . 5 x + x, )</strong>, or 7x inches. The height of the box is given to be 60 inches. According to the restriction, the sum of the perimeter of the base and the height of the box should not exceed 130 inches. Algebraically, this can be represented by <strong>7 x + 60 ≤ 130</strong>, or <strong>7 x ≤ 70</strong>. Dividing both sides of the inequality by 7 gives <strong>x ≤ 10</strong>. Since x represents the width of the box, x must also be a positive number. Therefore, the inequality <strong>0 < x, which ≤ 10</strong> represents all the allowable values of x that satisfy the given conditions.Choices B, C, and D are incorrect and may result from calculation errors or misreading the given information.",
hasFigure: false,
},
{
id: "b8e73b5b",
type: "mcq",
questionHtml:
"Ken is working this summer as part of a crew on a farm. He earned $8 per hour for the first 10 hours he worked this week. Because of his performance, his crew leader raised his salary to $10 per hour for the rest of the week. Ken saves 90% of his earnings from each week. What is the least number of hours he must work the rest of the week to save at least $270 for the week?",
choices: [
{ label: "A", text: "38" },
{ label: "B", text: "33" },
{ label: "C", text: "22" },
{ label: "D", text: "16" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Ken earned $8 per hour for the first 10 hours he worked, so he earned a total of $80 for the first 10 hours he worked. For the rest of the week, Ken was paid at the rate of $10 per hour. Let x be the number of hours he will work for the rest of the week. The total of Kens earnings, in dollars, for the week will be <strong>10 x + 80</strong>. He saves 90% of his earnings each week, so this week he will save <strong>0 . 9 · (10 x + 80, )</strong> dollars. The inequality <strong>0 . 9 · (10 x + 80, ) ≥ 270</strong> represents the condition that he will save at least $270 for the week. Factoring 10 out of the expression <strong>10 x + 80</strong> gives <strong>10 · (x + 8, )</strong>. The product of 10 and 0.9 is 9, so the inequality can be rewritten as <strong>9 · (x + 8, ) ≥ 270</strong>. Dividing both sides of this inequality by 9 yields <strong>x + 8 ≥ 30</strong>, so <strong>x ≥ 22</strong>. Therefore, the least number of hours Ken must work the rest of the week to save at least $270 for the week is 22.Choices A and B are incorrect because Ken can save $270 by working fewer hours than 38 or 33 for the rest of the week. Choice D is incorrect. If Ken worked 16 hours for the rest of the week, his total earnings for the week will be <strong>80 dollars + 160 dollars = 240 dollars</strong>, which is less than $270. Since he saves only 90% of his earnings each week, he would save even less than $240 for the week.",
hasFigure: false,
},
{
id: "d8539e09",
type: "mcq",
questionHtml:
"<strong>y < 6 x + 2</strong><br>For which of the following tables are all the values of <strong>x</strong> and their corresponding values of <strong>y</strong> solutions to the given inequality?",
choices: [
{
label: "A",
text: "<strong>x</strong><br><strong>y</strong><br><br><strong>3</strong><br><strong>20</strong><br><br><strong>5</strong><br><strong>32</strong><br><br><strong>7</strong><br><strong>44</strong>",
},
{
label: "B",
text: "<strong>x</strong><br><strong>y</strong><br><br><strong>3</strong><br><strong>16</strong><br><br><strong>5</strong><br><strong>36</strong><br><br><strong>7</strong><br><strong>40</strong>",
},
{
label: "C",
text: "<strong>x</strong><br><strong>y</strong><br><br><strong>3</strong><br><strong>16</strong><br><br><strong>5</strong><br><strong>28</strong><br><br><strong>7</strong><br><strong>40</strong>",
},
{
label: "D",
text: "<strong>x</strong><br><strong>y</strong><br><br><strong>3</strong><br><strong>24</strong><br><br><strong>5</strong><br><strong>36</strong><br><br><strong>7</strong><br><strong>48</strong>",
},
],
correctAnswer: "C",
explanation:
"Choice C is correct. All the tables in the choices have the same three values of <strong>x</strong>, so each of the three values of <strong>x</strong> can be substituted in the given inequality to compare the corresponding values of <strong>y</strong> in each of the tables. Substituting <strong>3</strong> for <strong>x</strong> in the given inequality yields <strong>y < 6 (3) + 2</strong>, or <strong>y < 20</strong>. Therefore, when <strong>x = 3</strong>, the corresponding value of <strong>y</strong> is less than <strong>20</strong>. Substituting <strong>5</strong> for <strong>x</strong> in the given inequality yields <strong>y < 6 (5) + 2</strong>, or <strong>y < 32</strong>. Therefore, when <strong>x = 5</strong>, the corresponding value of <strong>y</strong> is less than <strong>32</strong>. Substituting <strong>7</strong> for <strong>x</strong> in the given inequality yields <strong>y < 6 (7) + 2</strong>, or <strong>y < 44</strong>. Therefore, when <strong>x = 7</strong>, the corresponding value of <strong>y</strong> is less than <strong>44</strong>. For the table in choice C, when <strong>x = 3</strong>, the corresponding value of <strong>y</strong> is <strong>16</strong>, which is less than <strong>20</strong>; when <strong>x = 5</strong>, the corresponding value of <strong>y</strong> is <strong>28</strong>, which is less than <strong>32</strong>; when <strong>x = 7</strong>, the corresponding value of <strong>y</strong> is <strong>40</strong>, which is less than <strong>44</strong>. Therefore, the table in choice C gives values of <strong>x</strong> and their corresponding values of <strong>y</strong> that are all solutions to the given inequality.<br>Choice A is incorrect. In the table for choice A, when <strong>x = 3</strong>, the corresponding value of <strong>y</strong> is <strong>20</strong>, which is not less than <strong>20</strong>; when <strong>x = 5</strong>, the corresponding value of <strong>y</strong> is <strong>32</strong>, which is not less than <strong>32</strong>; when <strong>x = 7</strong>, the corresponding value of <strong>y</strong> is <strong>44</strong>, which is not less than <strong>44</strong>.<br>Choice B is incorrect. In the table for choice B, when <strong>x = 5</strong>, the corresponding value of <strong>y</strong> is <strong>36</strong>, which is not less than <strong>32</strong>.<br>Choice D is incorrect. In the table for choice D, when <strong>x = 3</strong>, the corresponding value of <strong>y</strong> is <strong>24</strong>, which is not less than <strong>20</strong>; when <strong>x = 5</strong>, the corresponding value of <strong>y</strong> is <strong>36</strong>, which is not less than <strong>32</strong>; when <strong>x = 7</strong>, the corresponding value of <strong>y</strong> is <strong>48</strong>, which is not less than <strong>44</strong>.",
hasFigure: false,
},
{
id: "e8f9e117",
type: "spr",
questionHtml:
"The formula above is Ohms law for an electric circuit with current I, in amperes, potential difference V, in volts, and resistance R, in ohms. A circuit has a resistance of 500 ohms, and its potential difference will be generated by n six-volt batteries that produce a total potential difference of <strong>6 n</strong> volts. If the circuit is to have a current of no more than 0.25 ampere, what is the greatest number, n, of six-volt batteries that can be used?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 20. For the given circuit, the resistance R is 500 ohms, and the total potential difference V generated by n batteries is <strong>6 n</strong> volts. Its also given that the circuit is to have a current of no more than 0.25 ampere, which can be expressed as <strong>I < 0 . 2 5</strong>. Since Ohms law says that <strong>I = V over R</strong>, the given values for V and R can be substituted for I in this inequality, which yields <strong>6 n over 500 < 0 . 2 5</strong>. Multiplying both sides of this inequality by 500 yields <strong>6 n < 125</strong>, and dividing both sides of this inequality by 6 yields <strong>n < 20 . 8 3 3</strong>. Since the number of batteries must be a whole number less than 20.833, the greatest number of batteries that can be used in this circuit is 20.",
hasFigure: false,
},
{
id: "ee2f611f",
type: "spr",
questionHtml:
"A local transit company sells a monthly pass for $95 that allows an unlimited number of trips of any length. Tickets for individual trips cost $1.50, $2.50, or $3.50, depending on the length of the trip. What is the minimum number of trips per month for which a monthly pass could cost less than purchasing individual tickets for trips?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 28. The minimum number of individual trips for which the cost of the monthly pass is less than the cost of individual tickets can be found by assuming the maximum cost of the individual tickets, $3.50. If n tickets costing $3.50 each are purchased in one month, the inequality 95 n represents this situation. Dividing both sides of the inequality by 3.50 yields 27.14 n, which is equivalent to n > 27.14. Since only a whole number of tickets can be purchased, it follows that 28 is the minimum number of trips.",
hasFigure: false,
},
{
id: "ee7b1de1",
type: "spr",
questionHtml:
"A small business owner budgets <strong>dollar sign 2, 200</strong> to purchase candles. The owner must purchase a minimum of <strong>200</strong> candles to maintain the discounted pricing. If the owner pays <strong>dollar sign 4.90</strong> per candle to purchase small candles and <strong>dollar sign 11.60</strong> per candle to purchase large candles, what is the maximum number of large candles the owner can purchase to stay within the budget and maintain the discounted pricing?",
choices: [],
correctAnswer: "182",
explanation:
"The correct answer is <strong>182</strong>. Let <strong>s</strong> represent the number of small candles the owner can purchase, and let <strong>script l</strong> represent the number of large candles the owner can purchase. Its given that the owner pays <strong>dollar sign 4.90</strong> per candle to purchase small candles and <strong>dollar sign 11.60</strong> per candle to purchase large candles. Therefore, the owner pays <strong>4.90 s</strong> dollars for <strong>s</strong> small candles and <strong>11.60 script l</strong> dollars for <strong>script l</strong> large candles, which means the owner pays a total of <strong>4.90 s + 11.60 script l</strong> dollars to purchase candles. Its given that the owner budgets <strong>dollar sign 2, 200</strong> to purchase candles. Therefore, <strong>4.90 s + 11.60 script l < or = 2, 200</strong>. Its also given that the owner must purchase a minimum of <strong>200</strong> candles. Therefore, <strong>s + script l > or = 200</strong>. The inequalities <strong>4.90 s + 11.60 script l < or = 2, 200</strong> and <strong>s + script l > or = 200</strong> can be combined into one compound inequality by rewriting the second inequality so that its left-hand side is equivalent to the left-hand side of the first inequality. Subtracting <strong>script l</strong> from both sides of the inequality <strong>s + script l > or = 200</strong> yields <strong>s > or = 200 script l</strong>. Multiplying both sides of this inequality by <strong>4.90</strong> yields <strong>4.90 s > or = 4.90 (200 script l)</strong>, or <strong>4.90 s > or = 980 4.90 script l</strong>. Adding <strong>11.60 script l</strong> to both sides of this inequality yields <strong>4.90 s + 11.60 script l > or = 980 4 . 90 script l + 11 . 60 script l</strong>, or <strong>4.90 s + 11.60 script l > or = 980 + 6.70 script l</strong>. This inequality can be combined with the inequality <strong>4.90 s + 11.60 script l < or = 2, 200</strong>, which yields the compound inequality <strong>980 + 6.70 script l < or = 4.90 s + 11.60 script l < or = 2, 200</strong>. It follows that <strong>980 + 6.70 script l < or = 2, 200</strong>. Subtracting <strong>980</strong> from both sides of this inequality yields <strong>6.70 script l < or = 2, 200</strong>. Dividing both sides of this inequality by <strong>6.70</strong> yields approximately <strong>script l < or = 182.09</strong>. Since the number of large candles the owner purchases must be a whole number, the maximum number of large candles the owner can purchase is the largest whole number less than <strong>182.09</strong>, which is <strong>182</strong>.",
hasFigure: false,
},
];

View File

@ -0,0 +1,775 @@
import { type PracticeQuestion } from "../../types/lesson";
export const LINES_ANGLES_EASY: PracticeQuestion[] = [
{
id: "087cdcfd",
type: "mcq",
questionHtml:
"In the figure, three lines intersect at point P. If <strong>x = 65</strong> and <strong>y = 75</strong>, what is the value of z ?",
choices: [
{ label: "A", text: "140" },
{ label: "B", text: "80" },
{ label: "C", text: "40" },
{ label: "D", text: "20" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The angle that is shown as lying between the y° angle and the z° angle is a vertical angle with the x° angle. Since vertical angles are congruent and <strong>x = 65</strong>, the angle between the y° angle and the z° angle measures 65°. Since the 65° angle, the y° angle, and the z° angle are adjacent and form a straight angle, it follows that the sum of the measures of these three angles is 180°, which is represented by the equation <strong>65 ° + y ° + z ° = 180 °</strong>. Its given that y = 75. Substituting 75 for y yields <strong>65 ° + 75 ° + z ° = 180 °</strong>, which can be rewritten as <strong>140 ° + z ° = 180 °</strong>. Subtracting 140° from both sides of this equation yields <strong>z ° = 40 °</strong>. Therefore, <strong>z = 40</strong>.Choice A is incorrect and may result from finding the value of <strong>x + y</strong> rather than z. Choices B and D are incorrect and may result from conceptual or computational errors.",
hasFigure: true,
figureUrl: "/practice-images/087cdcfd_img1.png",
},
{
id: "0bb39de4",
type: "mcq",
questionHtml:
"Triangles <strong>A B C</strong> and <strong>D E F</strong> are congruent, where <strong>A</strong> corresponds to <strong>D</strong>, and <strong>B</strong> and <strong>E</strong> are right angles. The measure of angle <strong>A</strong> is <strong>18 °</strong>. What is the measure of angle <strong>F</strong>?",
choices: [
{ label: "A", text: "<strong>18 °</strong>" },
{ label: "B", text: "<strong>72 °</strong>" },
{ label: "C", text: "<strong>90 °</strong>" },
{ label: "D", text: "<strong>162 °</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that triangle <strong>A B C</strong> is congruent to triangle <strong>D E F</strong>. Corresponding angles of congruent triangles are congruent and, therefore, have equal measure. Its given that angle <strong>A</strong> corresponds to angle <strong>D</strong>, and that the measure of angle <strong>A</strong> is <strong>18 °</strong>. It's also given that the measures of angles <strong>B</strong> and <strong>E</strong> are <strong>90 °</strong>. Since these angles have equal measure, they are corresponding angles. It follows that angle <strong>C</strong> corresponds to angle <strong>F</strong>. Let <strong>x °</strong> represent the measure of angle <strong>C</strong>. Since the sum of the measures of the interior angles of a triangle is <strong>180 °</strong>, it follows that <strong>18 ° + 90 ° + x ° = 180 °</strong>, or <strong>108 ° + x ° = 180 °</strong>. Subtracting <strong>108 °</strong> from both sides of this equation yields <strong>x ° = 72 °</strong>. Therefore, the measure of angle <strong>C</strong> is <strong>72 °</strong>. Since angle <strong>C</strong> corresponds to angle <strong>F</strong>, it follows that the measure of angle <strong>F</strong> is also <strong>72 °</strong>.<br>Choice A is incorrect. This is the measure of angle <strong>D</strong>, not the measure of angle <strong>F</strong>.<br>Choice C is incorrect. This is the measure of angle <strong>E</strong>, not the measure of angle <strong>F</strong>.<br>Choice D is incorrect. This is the sum of the measures of angles <strong>E</strong> and <strong>F</strong>, not the measure of angle <strong>F</strong>.",
hasFigure: false,
},
{
id: "0d3f51dc",
type: "mcq",
questionHtml:
"Clockwise from top left, the lines are labeled t, m, and n.<br>Line t intersects both line m and line n.<br>At the intersection of line t and line m, 1 angle is labeled clockwise from top left as follows:<br><br>Bottom left: x°<br><br>At the intersection of line t and line n, 1 angle is labeled clockwise from top left as follows:<br><br>Bottom right: 33°<br><br>A note indicates the figure is not drawn to scale.<br><br>In the figure, line <strong>m</strong> is parallel to line <strong>n</strong>, and line <strong>t</strong> intersects both lines. What is the value of <strong>x</strong>?",
choices: [
{ label: "A", text: "<strong>33</strong>" },
{ label: "B", text: "<strong>57</strong>" },
{ label: "C", text: "<strong>123</strong>" },
{ label: "D", text: "<strong>147</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Its given that line <strong>m</strong> is parallel to line <strong>n</strong>, and line <strong>t</strong> intersects both lines. It follows that line <strong>t</strong> is a transversal. When two lines are parallel and intersected by a transversal, exterior angles on the same side of the transversal are supplementary. Thus, <strong>x + 33 = 180</strong>. Subtracting <strong>33</strong> from both sides of this equation yields <strong>x = 147</strong>. Therefore, the value of <strong>x</strong> is <strong>147</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/0d3f51dc_svg1.svg",
},
{
id: "3563d76d",
type: "mcq",
questionHtml:
"At a certain time and day, the Washington Monument in Washington, DC, casts a shadow that is 300 feet long. At the same time, a nearby cherry tree casts a shadow that is 16 feet long. Given that the Washington Monument is approximately 555 feet tall, which of the following is closest to the height, in feet, of the cherry tree?",
choices: [
{ label: "A", text: "10" },
{ label: "B", text: "20" },
{ label: "C", text: "30" },
{ label: "D", text: "35" },
],
correctAnswer: "",
explanation:
"Choice C is correct. There is a proportional relationship between the height of an object and the length of its shadow. Let c represent the height, in feet, of the cherry tree. The given relationship can be expressed by the proportion <strong>555 over 300 = c over 16</strong>. Multiplying both sides of this equation by 16 yields <strong>c = 29 . 6</strong>. This height is closest to the value given in choice C, 30.Choices A, B, and D are incorrect and may result from calculation errors.",
hasFigure: false,
},
{
id: "36200a38",
type: "mcq",
questionHtml:
"<strong>The figure presents a triangle with a horizontal base. The left and right sides of the triangle are both extended past the top vertex of the triangle. The bottom left angle is labeled 70 °, and the bottom right angle is labeled 50 °. The angle above the left side of the triangle and below the extension of the right side of the triangle is labeled x °.</strong>In the figure above, two sides of a triangle are extended. What is the value of x ?",
choices: [
{ label: "A", text: "110" },
{ label: "B", text: "120" },
{ label: "C", text: "130" },
{ label: "D", text: "140" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The sum of the interior angles of a triangle is 180°. The measures of the two interior angles of the given triangle are shown. Therefore, the measure of the third interior angle is 180° 70° 50° = 60°. The angles of measures x° and 60° are supplementary, so their sum is 180°. Therefore, x = 180 60 = 120.Choice A is incorrect and may be the result of misinterpreting x° as supplementary to 70°. Choice C is incorrect and may be the result of misinterpreting x° as supplementary to 50°. Choice D is incorrect and may be the result of a calculation error.",
hasFigure: true,
figureUrl: "/practice-images/36200a38_img1.png",
},
{
id: "3828f53d",
type: "mcq",
questionHtml:
"In the figure above, lines m and n are parallel. What is the value of b ?",
choices: [
{ label: "A", text: "40" },
{ label: "B", text: "50" },
{ label: "C", text: "65" },
{ label: "D", text: "80" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Given that lines m and n are parallel, the angle marked 130° must be supplementary to the leftmost angle marked a° because they are same-side interior angles. Therefore, 130° + a° = 180°, which yields a = 50°. Lines <strong>l</strong> and m intersect at a right angle, so lines j, <strong>l</strong>, and m form a right triangle where the two acute angles are a° and b°. The acute angles of a right triangle are complementary, so a° + b° = 90°, which yields 50° + b° = 90°, and b = 40.Choice B is incorrect. This is the value of a, not b. Choice C is incorrect and may be the result of dividing 130° by 2. Choice D is incorrect and may be the result of multiplying b by 2.",
hasFigure: true,
figureUrl: "/practice-images/3828f53d_img1.png",
},
{
id: "3b4b5b1e",
type: "spr",
questionHtml:
"Clockwise from top left, the 3 lines are labeled t, j, and k.<br>Line t intersects both line j and line k.<br>At the intersection of line t and line j, 2 angles are labeled clockwise from top left as follows:<br><br>Bottom right: 133°<br>Bottom left: x°<br><br>A note indicates the figure is not drawn to scale.<br><br>In the figure, line <strong>j</strong> is parallel to line <strong>k</strong>. What is the value of <strong>x</strong>?",
choices: [],
correctAnswer: "47",
explanation:
"The correct answer is <strong>47</strong>. Based on the figure, the angle with measure <strong>x °</strong> and the angle with measure <strong>133 °</strong> together form a straight line. Therefore, these two angles are supplementary, so the sum of their measures is <strong>180 °</strong>. It follows that <strong>x + 133 = 180</strong>. Subtracting <strong>133</strong> from both sides of this equation yields <strong>x = 47</strong>.",
hasFigure: true,
figureUrl: "/practice-images/3b4b5b1e_svg1.svg",
},
{
id: "410bdbe6",
type: "mcq",
questionHtml:
"In the triangle above, <strong>a = 45</strong>. What is the value of b ?",
choices: [
{ label: "A", text: "52" },
{ label: "B", text: "59" },
{ label: "C", text: "76" },
{ label: "D", text: "104" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The sum of the measures of the three interior angles of a triangle is 180°. Therefore, <strong>31 + 2 b + a = 180</strong>. Since its given that <strong>a = 45</strong>, it follows that <strong>31 + 2 b + 45 = 180</strong>, or <strong>2 b = 104</strong>. Dividing both sides of this equation by 2 yields <strong>b = 52</strong>.Choice B is incorrect and may result from a calculation error. Choice C is incorrect. This is the value of <strong>a + 31</strong>. Choice D is incorrect. This is the value of <strong>2 b</strong>.",
hasFigure: true,
figureUrl: "/practice-images/410bdbe6_img1.png",
},
{
id: "42b4493b",
type: "mcq",
questionHtml:
"In a right triangle, the measure of one of the acute angles is <strong>51 °</strong>. What is the measure, in degrees, of the other acute angle?",
choices: [
{ label: "A", text: "<strong>6</strong>" },
{ label: "B", text: "<strong>39</strong>" },
{ label: "C", text: "<strong>49</strong>" },
{ label: "D", text: "<strong>51</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The sum of the measures of the interior angles of a triangle is <strong>180</strong> degrees. Since the triangle is a right triangle, it has one angle that measures <strong>90</strong> degrees. Therefore, the sum of the measures, in degrees, of the remaining two angles is <strong>180 90</strong>, or <strong>90</strong>. Its given that the measure of one of the acute angles in the triangle is <strong>51</strong> degrees. Therefore, the measure, in degrees, of the other acute angle is <strong>90 51</strong>, or <strong>39</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect. This is the measure, in degrees, of the acute angle whose measure is given.",
hasFigure: false,
},
{
id: "5207e508",
type: "mcq",
questionHtml:
"Clockwise from top left, the 3 lines are labeled t, m, and n.<br>Line t intersects both line m and line n.<br>At the intersection of line t and line m, 1 angle is labeled clockwise from top left as follows:<br><br>Bottom left: 170°<br><br>At the intersection of line t and line n, 1 angle is labeled clockwise from top left as follows:<br><br>Bottom left: w°<br><br>A note indicates the figure is not drawn to scale.<br><br>In the figure, line <strong>m</strong> is parallel to line <strong>n</strong>. What is the value of <strong>w</strong>?",
choices: [
{ label: "A", text: "<strong>17</strong>" },
{ label: "B", text: "<strong>30</strong>" },
{ label: "C", text: "<strong>70</strong>" },
{ label: "D", text: "<strong>170</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. It's given that lines <strong>m</strong> and <strong>n</strong> are parallel. Since line <strong>t</strong> intersects both lines <strong>m</strong> and <strong>n</strong>, it's a transversal. The angles in the figure marked as <strong>170 °</strong> and <strong>w °</strong> are on the same side of the transversal, where one is an interior angle with line <strong>m</strong> as a side, and the other is an exterior angle with line <strong>n</strong> as a side. Thus, the marked angles are corresponding angles. When two parallel lines are intersected by a transversal, corresponding angles are congruent and, therefore, have equal measure. It follows that <strong>w ° = 170 °</strong>. Therefore, the value of <strong>w</strong> is <strong>170</strong>. <br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/5207e508_svg1.svg",
},
{
id: "5733ce30",
type: "mcq",
questionHtml:
"In the given figure, <strong>side A C</strong> extends to point D. If the measure of <strong>angle B A C</strong> is equal to the measure of <strong>angle B C A</strong>, what is the value of x ?",
choices: [
{ label: "A", text: "110" },
{ label: "B", text: "70" },
{ label: "C", text: "55" },
{ label: "D", text: "40" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Since <strong>angle B C D</strong> and <strong>angle B C A</strong> form a linear pair of angles, their measures sum to 180°. Its given that the measure of <strong>angle B C D</strong> is 110°. Therefore, <strong>110 ° + angle B C A = 180 °</strong>. Subtracting 110° from both sides of this equation gives the measure of <strong>angle B C A</strong> as 70°. Its also given that the measure of <strong>angle B A C</strong> is equal to the measure of <strong>angle B C A</strong>. Thus, the measure of <strong>angle B A C</strong> is also 70°. The measures of the interior angles of a triangle sum to 180°. Thus, <strong>70 ° + 70 ° + x ° = 180 °</strong>. Combining like terms on the left-hand side of this equation yields <strong>140 ° + x ° = 180 °</strong>. Subtracting 140° from both sides of this equation yields <strong>x ° = 40 °</strong>, or <strong>x = 40</strong>.Choice A is incorrect. This is the value of the measure of <strong>angle B C D</strong>. Choice B is incorrect. This is the value of the measure of each of the other two interior angles, <strong>angle B C A</strong> and <strong>angle B A C</strong>. Choice C is incorrect and may result from an error made when identifying the relationship between the exterior angle of a triangle and the interior angles of the triangle.",
hasFigure: true,
figureUrl: "/practice-images/5733ce30_img1.png",
},
{
id: "992f4e93",
type: "mcq",
questionHtml:
"In the figure above, lines <strong>l</strong> and k are parallel. What is the value of a ?",
choices: [
{ label: "A", text: "26" },
{ label: "B", text: "64" },
{ label: "C", text: "116" },
{ label: "D", text: "154" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Since lines <strong>l</strong> and k are parallel, corresponding angles formed by the intersection of line j with lines <strong>l</strong> and k are congruent. Therefore, the angle with measure a° must be the supplement of the angle with measure 64°. The sum of two supplementary angles is 180°, so a = 180 64 = 116.Choice A is incorrect and likely results from thinking the angle with measure a° is the complement of the angle with measure 64°. Choice B is incorrect and likely results from thinking the angle with measure a° is congruent to the angle with measure 64°. Choice D is incorrect and likely results from a conceptual or computational error.",
hasFigure: true,
figureUrl: "/practice-images/992f4e93_img1.png",
},
{
id: "a6dbad6b",
type: "mcq",
questionHtml:
"<strong>The figure presents 2 parallel lines l and m, which are almost horizontal, with l above m. A from the left on m, moves up and to the right, intersects, and ends above l. Another from the right on m, moves up and to the left, intersects, and ends at the same . as the other line segment, above l. The angle at the . where the two line segments meet is labeled x °. The angle above l and to the left of the right is labeled z °. The angle above m and to the right of the left is labeled y °. The figure is not drawn to scale</strong>In the figure above, lines <strong>l</strong> and m are parallel, <strong>y = 20</strong>, and <strong>z = 60</strong>. What is the value of x ?",
choices: [
{ label: "A", text: "120" },
{ label: "B", text: "100" },
{ label: "C", text: "90" },
{ label: "D", text: "80" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Let the measure of the third angle in the smaller triangle be <strong>a, °</strong>. Since lines <strong>l</strong> and m are parallel and cut by transversals, it follows that the corresponding angles formed are congruent. So <strong>a ° = y °, which = 20 °</strong>. The sum of the measures of the interior angles of a triangle is <strong>180 °</strong>, which for the interior angles in the smaller triangle yields <strong>a + x + z = 180</strong>. Given that <strong>z = 60</strong> and <strong>a = 20</strong>, it follows that <strong>20 + x + 60 = 180</strong>. Solving for x gives <strong>x = 180 60 20</strong>, or <strong>x = 100</strong>.Choice A is incorrect and may result from incorrectly assuming that angles <strong>x + z = 180</strong>. Choice C is incorrect and may result from incorrectly assuming that the smaller triangle is a right triangle, with x as the right angle. Choice D is incorrect and may result from a misunderstanding of the exterior angle theorem and incorrectly assuming that <strong>x = y + z</strong>.",
hasFigure: true,
figureUrl: "/practice-images/a6dbad6b_img1.png",
},
{
id: "afa3c48b",
type: "mcq",
questionHtml:
"Clockwise from top left, the 3 lines are labeled l, m, and n.<br>Line l intersects both line m and line n.<br>At the intersection of line l and line m, 1 angle is labeled clockwise from top left as follows:<br><br>Top right: x°<br><br>At the intersection of line l and line n, 1 angle is labeled clockwise from top left as follows:<br><br>Top left: 26°<br><br>A note indicates the figure is not drawn to scale.<br><br>In the figure shown, line <strong>m</strong> is parallel to line <strong>n</strong>. What is the value of <strong>x</strong>?",
choices: [
{ label: "A", text: "<strong>13</strong>" },
{ label: "B", text: "<strong>26</strong>" },
{ label: "C", text: "<strong>52</strong>" },
{ label: "D", text: "<strong>154</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The sum of consecutive interior angles between two parallel lines and on the same side of the transversal is <strong>180</strong> degrees. Since it's given that line <strong>m</strong> is parallel to line <strong>n</strong>, it follows that <strong>x + 26 = 180</strong>. Subtracting <strong>26</strong> from both sides of this equation yields <strong>154</strong>. Therefore, the value of <strong>x</strong> is <strong>154</strong>.<br>Choice A is incorrect. This is half of the given angle measure.<br>Choice B is incorrect. This is the value of the given angle measure.<br>Choice C is incorrect. This is twice the value of the given angle measure.",
hasFigure: true,
figureUrl: "/practice-images/afa3c48b_svg1.svg",
},
{
id: "c24e1bda",
type: "mcq",
questionHtml:
"Clockwise from top left, the 3 lines are labeled t, m, and n.<br>Line t intersects both line m and line n.<br>At the intersection of line t and line m, 1 angle is labeled clockwise from top left as follows:<br><br>Bottom left: 134°<br><br>At the intersection of line t and line n, 1 angle is labeled clockwise from top left as follows:<br><br>Bottom left: w°<br><br>A note indicates the figure is not drawn to scale. <br><br>In the figure, line <strong>m</strong> is parallel to line <strong>n</strong>. What is the value of <strong>w</strong>?",
choices: [
{ label: "A", text: "<strong>13</strong>" },
{ label: "B", text: "<strong>34</strong>" },
{ label: "C", text: "<strong>66</strong>" },
{ label: "D", text: "<strong>134</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. It's given that lines <strong>m</strong> and <strong>n</strong> are parallel. Since line <strong>t</strong> intersects both lines <strong>m</strong> and <strong>n</strong>, it's a transversal. The angles in the figure marked as <strong>134 °</strong> and <strong>w °</strong> are on the same side of the transversal, where one is an interior angle with line <strong>m</strong> as a side, and the other is an exterior angle with line <strong>n</strong> as a side. Thus, the marked angles are corresponding angles. When two parallel lines are intersected by a transversal, corresponding angles are congruent and, therefore, have equal measure. It follows that <strong>w ° = 134 °</strong>. Therefore, the value of <strong>w</strong> is <strong>134</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/c24e1bda_svg1.svg",
},
{
id: "c8d60e48",
type: "mcq",
questionHtml:
"In the given triangle, <strong>the length of side A, B = the length of side A, C</strong> and <strong>angle A, B C</strong> has a measure of <strong>67 °</strong>. What is the value of x ?",
choices: [
{ label: "A", text: "36" },
{ label: "B", text: "46" },
{ label: "C", text: "58" },
{ label: "D", text: "70" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Since <strong>the length of A, B = the length of A, C</strong>, the measures of their corresponding angles, <strong>angle A, B C</strong> and <strong>angle A, C B</strong>, are equal. Since <strong>angle A, B C</strong> has a measure of <strong>67 °</strong>, the measure of <strong>angle A, C B</strong> is also <strong>67 °</strong>. Since the sum of the measures of the interior angles in a triangle is <strong>180 °</strong>, it follows that <strong>67 + 67 + x = 180</strong>, or <strong>134 + x = 180</strong>. Subtracting by 134 on both sides of this equation yields <strong>x = 46</strong>.Choices A, C, and D are incorrect and may result from calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/c8d60e48_img1.png",
},
{
id: "cbe8ca31",
type: "mcq",
questionHtml:
"In <strong>triangle X Y Z</strong>, the measure of <strong>angle X</strong> is <strong>24 °</strong> and the measure of <strong>angle Y</strong> is <strong>98 °</strong>. What is the measure of <strong>angle Z</strong>?",
choices: [
{ label: "A", text: "<strong>58 °</strong>" },
{ label: "B", text: "<strong>74 °</strong>" },
{ label: "C", text: "<strong>122 °</strong>" },
{ label: "D", text: "<strong>212 °</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The triangle angle sum theorem states that the sum of the measures of the interior angles of a triangle is <strong>180 °</strong>. It's given that in <strong>triangle X Y Z</strong>, the measure of <strong>angle X</strong> is <strong>24 °</strong> and the measure of <strong>angle Y</strong> is <strong>98 °</strong>. It follows that the measure of <strong>angle Z</strong> is <strong>(180 24 98) °</strong>, or <strong>58 °</strong>.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect. This is the sum of the measures of <strong>angle X</strong> and <strong>angle Y</strong>, not the measure of <strong>angle Z</strong>.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "cf0d3050",
type: "spr",
questionHtml:
"Clockwise from top left, the 3 lines are labeled, c, s, and t.<br>Line c intersects both line s and line t.<br>At the intersection of line c and line s, 1 angle is labeled clockwise from top left as follows:<br><br>Top right: x°<br><br>At the intersection of line c and line t, 1 angle is labeled clockwise from top left as follows:<br><br>Top left: 110°<br><br>A note indicates the figure is not drawn to scale.<br><br>In the figure shown, line <strong>c</strong> intersects parallel lines <strong>s</strong> and <strong>t</strong>. What is the value of <strong>x</strong>?",
choices: [],
correctAnswer: "70",
explanation:
"The correct answer is <strong>70</strong>. Based on the figure, the angle with measure <strong>110 °</strong> and the angle vertical to the angle with measure <strong>x °</strong> are same side interior angles. Since vertical angles are congruent, the angle vertical to the angle with measure <strong>x °</strong> also has measure <strong>x °</strong>. Its given that lines <strong>s</strong> and <strong>t</strong> are parallel. Therefore, same side interior angles between lines <strong>s</strong> and <strong>t</strong> are supplementary. It follows that <strong>x + 110 = 180</strong>. Subtracting <strong>110</strong> from both sides of this equation yields <strong>x = 70</strong>.",
hasFigure: true,
figureUrl: "/practice-images/cf0d3050_svg1.svg",
},
{
id: "d5f349b7",
type: "mcq",
questionHtml:
"Right triangle upper P upper Q upper R is labeled as follows:<br><br>Angle upper R is a right angle.<br><br>Right triangle upper S upper T upper U is labeled as follows:<br><br>Angle upper U is a right angle.<br><br>A note indicates the figures are not drawn to scale.<br><br>Right triangles <strong>P Q R</strong> and <strong>S T U</strong> are similar, where <strong>P</strong> corresponds to <strong>S</strong>. If the measure of angle <strong>Q</strong> is <strong>18 °</strong>, what is the measure of angle <strong>S</strong>?",
choices: [
{ label: "A", text: "<strong>18 °</strong>" },
{ label: "B", text: "<strong>72 °</strong>" },
{ label: "C", text: "<strong>82 °</strong>" },
{ label: "D", text: "<strong>162 °</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. In similar triangles, corresponding angles are congruent. Its given that right triangles <strong>P Q R</strong> and <strong>S T U</strong> are similar, where angle <strong>P</strong> corresponds to angle <strong>S</strong>. It follows that angle <strong>P</strong> is congruent to angle <strong>S</strong>. In the triangles shown, angle <strong>R</strong> and angle <strong>U</strong> are both marked as right angles, so angle <strong>R</strong> and angle <strong>U</strong> are corresponding angles. It follows that angle <strong>Q</strong> and angle <strong>T</strong> are corresponding angles, and thus, angle <strong>Q</strong> is congruent to angle <strong>T</strong>. Its given that the measure of angle <strong>Q</strong> is <strong>18 °</strong>, so the measure of angle <strong>T</strong> is also <strong>18 °</strong>. Angle <strong>U</strong> is a right angle, so the measure of angle <strong>U</strong> is <strong>90 °</strong>. The sum of the measures of the interior angles of a triangle is <strong>180 °</strong>. Thus, the sum of the measures of the interior angles of triangle <strong>S T U</strong> is <strong>180</strong> degrees. Let <strong>s</strong> represent the measure, in degrees, of angle <strong>S</strong>. It follows that <strong>s + 18 + 90 = 180</strong>, or <strong>s + 108 = 180</strong>. Subtracting <strong>108</strong> from both sides of this equation yields <strong>s = 72</strong>. Therefore, if the measure of angle <strong>Q</strong> is <strong>18</strong> degrees, then the measure of angle <strong>S</strong> is <strong>72</strong> degrees.<br>Choice A is incorrect. This is the measure of angle <strong>T</strong>.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect. This is the sum of the measures of angle <strong>S</strong> and angle <strong>U</strong>.",
hasFigure: true,
figureUrl: "/practice-images/d5f349b7_svg1.svg",
},
{
id: "dfc420b2",
type: "mcq",
questionHtml:
"In the figure above, <strong>A, D</strong> intersects <strong>B E</strong> at C. If <strong>x = 100</strong>, what is the value of y ?",
choices: [
{ label: "A", text: "100" },
{ label: "B", text: "90" },
{ label: "C", text: "80" },
{ label: "D", text: "60" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that <strong>x = 100</strong>; therefore, substituting 100 for x in triangle ABC gives two known angle measures for this triangle. The sum of the measures of the interior angles of any triangle equals 180°. Subtracting the two known angle measures of triangle ABC from 180° gives the third angle measure: <strong>180 ° 100 ° 20 ° = 60 °</strong>. This is the measure of angle BCA. Since vertical angles are congruent, the measure of angle DCE is also 60°. Subtracting the two known angle measures of triangle CDE from 180° gives the third angle measure: <strong>180 ° 60 ° 40 ° = 80 °</strong>. Therefore, the value of y is 80.Choice A is incorrect and may result from a calculation error. Choice B is incorrect and may result from classifying angle CDE as a right angle. Choice D is incorrect and may result from finding the measure of angle BCA or DCE instead of the measure of angle CDE.",
hasFigure: true,
figureUrl: "/practice-images/dfc420b2_img1.png",
},
{
id: "f1747a6a",
type: "mcq",
questionHtml:
"In triangle <strong>A B C</strong>, the measure of angle <strong>B</strong> is <strong>52 °</strong> and the measure of angle <strong>C</strong> is <strong>17 °</strong>. What is the measure of angle <strong>A</strong>?",
choices: [
{ label: "A", text: "<strong>21 °</strong>" },
{ label: "B", text: "<strong>35 °</strong>" },
{ label: "C", text: "<strong>69 °</strong>" },
{ label: "D", text: "<strong>111 °</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The sum of the angle measures of a triangle is <strong>180 °</strong>. Adding the measures of angles <strong>B</strong> and <strong>C</strong> gives <strong>52 + 17 = 69 °</strong>. Therefore, the measure of angle <strong>A</strong> is <strong>180 69 = 111 °</strong>.<br>Choice A is incorrect and may result from subtracting the sum of the measures of angles <strong>B</strong> and <strong>C</strong> from <strong>90 °</strong>, instead of from <strong>180 °</strong>.<br>Choice B is incorrect and may result from subtracting the measure of angle <strong>C</strong> from the measure of angle <strong>B</strong>.<br>Choice C is incorrect and may result from adding the measures of angles <strong>B</strong> and <strong>C</strong> but not subtracting the result from <strong>180 °</strong>.",
hasFigure: false,
},
{
id: "f9d40000",
type: "mcq",
questionHtml:
"In <strong>triangle X Y Z</strong>, the measure of <strong>angle X</strong> is <strong>23 °</strong> and the measure of <strong>angle Y</strong> is <strong>66 °</strong>. What is the measure of <strong>angle Z</strong>?",
choices: [
{ label: "A", text: "<strong>43 °</strong>" },
{ label: "B", text: "<strong>89 °</strong>" },
{ label: "C", text: "<strong>91 °</strong>" },
{ label: "D", text: "<strong>179 °</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The triangle angle sum theorem states that the sum of the measures of the interior angles of a triangle is <strong>180 °</strong>. It's given that in <strong>triangle X Y Z</strong>, the measure of <strong>angle X</strong> is <strong>23 °</strong> and the measure of <strong>angle Y</strong> is <strong>66 °</strong>. It follows that the measure of <strong>angle Z</strong> is <strong>(180 23 66) °</strong>, or <strong>91 °</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect. This is the sum of the measures of <strong>angle X</strong> and <strong>angle Y</strong>, not the measure of <strong>angle Z</strong>.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
];
export const LINES_ANGLES_MEDIUM: PracticeQuestion[] = [
{
id: "1c3d613c",
type: "spr",
questionHtml:
"Triangle ABC and triangle DEF are shown. The relationship between the side lengths of the two triangles is such that <strong>the length of side A, B, over, the length of side D E = the length of side B C, over, the length of side E F, which = the length of side A, C, over, the length of side D F, which = 3</strong>. If the measure of angle BAC is 20°, what is the measure, in degrees, of angle EDF ? (Disregard the degree symbol when gridding your answer.)",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 20. By the equality given, the three pairs of corresponding sides of the two triangles are in the same proportion. By the side-side-side (SSS) similarity theorem, triangle ABC is similar to triangle DEF. In similar triangles, the measures of corresponding angles are congruent. Since angle BAC corresponds to angle EDF, these two angles are congruent and their measures are equal. Its given that the measure of angle BAC is 20°, so the measure of angle EDF is also 20°.",
hasFigure: true,
figureUrl: "/practice-images/1c3d613c_img1.png",
},
{
id: "2adbf1b1",
type: "mcq",
questionHtml:
"Clockwise from top left, the 3 lines are labeled t, m, and n.<br>Line t intersects both line m and line n.<br>At the intersection of line t and line m, 2 angles are labeled clockwise from top left as follows:<br><br>Top right: x°<br>Bottom left: y°<br><br>At the intersection of line t and line n, 1 angle is labeled clockwise from top left as follows:<br><br>Top left: z°<br><br>A note indicates the figure is not drawn to scale.<br><br>In the figure, lines <strong>m</strong> and <strong>n</strong> are parallel. If <strong>x = 6 k + 13</strong> and <strong>y = 8 k 29</strong>, what is the value of <strong>z</strong>?",
choices: [
{ label: "A", text: "<strong>3</strong>" },
{ label: "B", text: "<strong>21</strong>" },
{ label: "C", text: "<strong>41</strong>" },
{ label: "D", text: "<strong>139</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Vertical angles, which are angles that are opposite each other when two lines intersect, are congruent. The figure shows that lines <strong>t</strong> and <strong>m</strong> intersect. It follows that the angle with measure <strong>x °</strong> and the angle with measure <strong>y °</strong> are vertical angles, so <strong>x = y</strong>. It's given that <strong>x = 6 k + 13</strong> and <strong>y = 8 k 29</strong>. Substituting <strong>6 k + 13</strong> for <strong>x</strong> and <strong>8 k 29</strong> for <strong>y</strong> in the equation <strong>x = y</strong> yields <strong>6 k + 13 = 8 k 29</strong>. Subtracting <strong>6 k</strong> from both sides of this equation yields <strong>13 = 2 k 29</strong>. Adding <strong>29</strong> to both sides of this equation yields <strong>42 = 2 k</strong>, or <strong>2 k = 42</strong>. Dividing both sides of this equation by <strong>2</strong> yields <strong>k = 21</strong>. It's given that lines <strong>m</strong> and <strong>n</strong> are parallel, and the figure shows that lines <strong>m</strong> and <strong>n</strong> are intersected by a transversal, line <strong>t</strong>. If two parallel lines are intersected by a transversal, then the same-side interior angles are supplementary. It follows that the same-side interior angles with measures <strong>y °</strong> and <strong>z °</strong> are supplementary, so <strong>y + z = 180</strong>. Substituting <strong>8 k 29</strong> for <strong>y</strong> in this equation yields <strong>8 k 29 + z = 180</strong>. Substituting <strong>21</strong> for <strong>k</strong> in this equation yields <strong>8 (21) 29 + z = 180</strong>, or <strong>139 + z = 180</strong>. Subtracting <strong>139</strong> from both sides of this equation yields <strong>z = 41</strong>. Therefore, the value of <strong>z</strong> is <strong>41</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect. This is the value of <strong>k</strong>, not <strong>z</strong>.<br>Choice D is incorrect. This is the value of <strong>x</strong> or <strong>y</strong>, not <strong>z</strong>.",
hasFigure: true,
figureUrl: "/practice-images/2adbf1b1_svg1.svg",
},
{
id: "4ff7b652",
type: "mcq",
questionHtml:
"Right triangles <strong>L M N</strong> and <strong>P Q R</strong> are similar, where <strong>L</strong> and <strong>M</strong> correspond to <strong>P</strong> and <strong>Q</strong>, respectively. Angle <strong>M</strong> has a measure of <strong>53 °</strong>. What is the measure of angle <strong>Q</strong>?",
choices: [
{ label: "A", text: "<strong>37 °</strong>" },
{ label: "B", text: "<strong>53 °</strong>" },
{ label: "C", text: "<strong>127 °</strong>" },
{ label: "D", text: "<strong>143 °</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that triangle <strong>L M N</strong> is similar to triangle <strong>P Q R</strong>. Corresponding angles of similar triangles are congruent. Since angle <strong>M</strong> and angle <strong>Q</strong> correspond to each other, they must be congruent. Therefore, if the measure of angle <strong>M</strong> is <strong>53 °</strong>, then the measure of angle <strong>Q</strong> is also <strong>53 °</strong>.<br>Choice A is incorrect and may result from concluding that angle <strong>M</strong> and angle <strong>Q</strong> are complementary rather than congruent.<br>Choice C is incorrect and may result from concluding that angle <strong>M</strong> and angle <strong>Q</strong> are supplementary rather than congruent.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "686b5212",
type: "spr",
questionHtml:
"Clockwise from top left, the 3 lines are labeled s, q, and r.<br>Line s intersects both line q and line r.<br>At the intersection of line s and line q, 1 angle is labeled clockwise from top left as follows:<br><br>Top right: 58°<br><br>At the intersection of line s and line r, 1 angle is labeled clockwise from top left as follows:<br><br>Top left: y°<br><br>A note indicates the figure is not drawn to scale.<br><br>In the figure, line <strong>q</strong> is parallel to line <strong>r</strong>, and both lines are intersected by line <strong>s</strong>. If <strong>y = 2 x + 8</strong>, what is the value of <strong>x</strong>?",
choices: [],
correctAnswer: "57",
explanation:
"The correct answer is <strong>57</strong>. Based on the figure, the angle with measure <strong>y °</strong> and the angle vertical to the angle with measure <strong>58 °</strong> are same side interior angles. Since vertical angles are congruent, the angle vertical to the angle with measure <strong>58 °</strong> also has measure <strong>58 °</strong>. Its given that lines <strong>q</strong> and <strong>r</strong> are parallel. Therefore, same side interior angles between lines <strong>q</strong> and <strong>r</strong> are supplementary. It follows that <strong>y + 58 = 180</strong>. If <strong>y = 2 x + 8</strong>, then the value of <strong>x</strong> can be found by substituting <strong>2 x + 8</strong> for <strong>y</strong> in the equation <strong>y + 58 = 180</strong>, which yields <strong>(2 x + 8) + 58 = 180</strong>, or <strong>2 x + 66 = 180</strong>. Subtracting <strong>66</strong> from both sides of this equation yields <strong>2 x = 114</strong>. Dividing both sides of this equation by <strong>2</strong> yields <strong>x = 57</strong>. Thus, if <strong>y = 2 x + 8</strong>, the value of <strong>x</strong> is <strong>57</strong>.",
hasFigure: true,
figureUrl: "/practice-images/686b5212_svg1.svg",
},
{
id: "6dd463ca",
type: "mcq",
questionHtml:
"In the figure above, segments AE and BD are parallel. If angle BDC measures 58° and angle ACE measures 62°, what is the measure of angle CAE ?",
choices: [
{ label: "A", text: "58°" },
{ label: "B", text: "60°" },
{ label: "C", text: "62°" },
{ label: "D", text: "120°" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that angle ACE measures <strong>62 °</strong>. Since segments AE and BD are parallel, angles BDC and CEA are congruent. Therefore, angle CEA measures <strong>58 °</strong>. The sum of the measures of angles ACE, CEA, and CAE is <strong>180 °</strong> since the sum of the interior angles of triangle ACE is equal to <strong>180 °</strong>. Let the measure of angle CAE be <strong>x °</strong>. Therefore, <strong>62 + 58 + x = 180</strong>, which simplifies to <strong>x = 60</strong>. Thus, the measure of angle CAE is <strong>60 °</strong>.Choice A is incorrect. This is the measure of angle AEC, not that of angle CAE. Choice C is incorrect. This is the measure of angle ACE, not that of CAE. Choice D is incorrect. This is the sum of the measures of angles ACE and CEA.",
hasFigure: true,
figureUrl: "/practice-images/6dd463ca_img1.png",
},
{
id: "81b664bc",
type: "mcq",
questionHtml:
"<strong>The figure presents quadrilateral A, C D F, where side A, F and side C D are horizontal, and side C D lies above side A, F. Side C D is longer than side A, F. . B lies on left side A, C, and . E lies on right side D F. B E, which is horizontal, divides quadrilateral A, C D F into two quadrilaterals, A, B E F and B C D E.</strong>In the figure above, <strong>side A, F</strong>, <strong>B E</strong>, and <strong>side C D</strong> are parallel. Points B and E lie on <strong>side A, C</strong> and <strong>side F D</strong>, respectively. If <strong>the length of A, B = 9, the length of B C = 18 . 5</strong>, and <strong>the length of F E = 8 . 5</strong>, what is the length of <strong>E D</strong>, to the nearest tenth?",
choices: [
{ label: "A", text: "16.8" },
{ label: "B", text: "17.5" },
{ label: "C", text: "18.4" },
{ label: "D", text: "19.6" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Since <strong>A F</strong>, <strong>B E</strong>, and <strong>C D</strong> are parallel, quadrilaterals <strong>A F E B</strong> and <strong>B E D C</strong> are similar. Let x represent the length of <strong>E D</strong>. With similar figures, the ratios of the lengths of corresponding sides are equal. It follows that <strong>9 over 18 . 5 = 8 . 5 over x</strong>. Multiplying both sides of this equation by 18.5 and by x yields <strong>9 x = 18 . 5 · 8 . 5</strong>, or <strong>9 x = 157 . 2 5</strong>. Dividing both sides of this equation by 9 yields <strong>x = 17 . 4 7</strong>, which to the nearest tenth is 17.5.Choices A, C, and D are incorrect and may result from errors made when setting up the proportion.",
hasFigure: true,
figureUrl: "/practice-images/81b664bc_img1.png",
},
{
id: "901e3285",
type: "mcq",
questionHtml:
"In triangle ABC, the measure of angle A is <strong>50 °</strong>. If triangle ABC is isosceles, which of the following is NOT a possible measure of angle B ?",
choices: [
{ label: "A", text: "<strong>50 °</strong>" },
{ label: "B", text: "<strong>65 °</strong>" },
{ label: "C", text: "<strong>80 °</strong>" },
{ label: "D", text: "<strong>100 °</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The sum of the three interior angles in a triangle is <strong>180 °</strong>. Its given that angle A measures <strong>50 °</strong>. If angle B measured <strong>100 °</strong>, the measure of angle C would be <strong>180 ° (50 ° + 100 °, ) = 30 °</strong>. Thus, the measures of the angles in the triangle would be <strong>50 °</strong>, <strong>100 °</strong>, and <strong>30 °</strong>. However, an isosceles triangle has two angles of equal measure. Therefore, angle B cant measure <strong>100 °</strong>.Choice A is incorrect. If angle B has measure <strong>50 °</strong>, then angle C would measure <strong>180 ° (50 ° + 50 °, ) = 80 °</strong>, and <strong>50 °</strong>, <strong>50 °</strong>, and <strong>80 °</strong> could be the angle measures of an isosceles triangle. Choice B is incorrect. If angle B has measure <strong>65 °</strong>, then angle C would measure <strong>180 ° (65 ° + 50 °, ) = 65 °</strong>, and <strong>50 °</strong>, <strong>65 °</strong>, and <strong>65 °</strong> could be the angle measures of an isosceles triangle. Choice C is incorrect. If angle B has measure <strong>80 °</strong>, then angle C would measure <strong>180 ° (80 ° + 50 °, ) = 50 °</strong>, and <strong>50 °</strong>, <strong>80 °</strong>, and <strong>50 °</strong> could be the angle measures of an isosceles triangle.",
hasFigure: false,
},
{
id: "933fee1a",
type: "mcq",
questionHtml:
"Triangles ABC and DEF are shown above. Which of the following is equal to the ratio <strong>B C over A, B</strong>?",
choices: [
{ label: "A", text: "<strong>D E over D F</strong>" },
{ label: "B", text: "<strong>D F over D E</strong>" },
{ label: "C", text: "<strong>D F over E F</strong>" },
{ label: "D", text: "<strong>E F over D E</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. In right triangle ABC, the measure of angle B must be 58° because the sum of the measure of angle A, which is 32°, and the measure of angle B is 90°. Angle D in the right triangle DEF has measure 58°. Hence, triangles ABC and DEF are similar (by angle-angle similarity). Since <strong>side B C</strong> is the side opposite to the angle with measure 32° and AB is the hypotenuse in right triangle ABC, the ratio <strong>the length of side B C over the length of side A, B</strong> is equal to <strong>the length of side D F over the length of side D E</strong>.Alternate approach: The trigonometric ratios can be used to answer this question. In right triangle ABC, the ratio <strong>the length of side B C over the length of side A, B = the sin of 32 °</strong>. The angle E in triangle DEF has measure 32° because <strong>the measure of angle D + the measure of angle E = 90 °</strong>. In triangle DEF, the ratio <strong>the length of side D F over the length of side D E = the sin of 32 °</strong>. Therefore, <strong>the length of side D F over the length of side D E = the length of side B C over the length of side A, B</strong>.<br>Choice A is incorrect because <strong>the length of side D E over the length of side D F</strong> is the reciprocal of the ratio <strong>the length of side B C over the length of side A, B</strong>. Choice C is incorrect because <strong>the length of side D F over the length of side D E = the length of side B C over the length of side A, C</strong>, not <strong>the length of side B C over the length of side A, B</strong>. Choice D is incorrect because <strong>the length of side E F over the length of side D E = the length of side A, C over the length of side A, B</strong>, not <strong>the length of side B C over the length of side A, B</strong>.",
hasFigure: true,
figureUrl: "/practice-images/933fee1a_img1.png",
},
{
id: "94364a79",
type: "mcq",
questionHtml:
"Two nearby trees are perpendicular to the ground, which is flat. One of these trees is <strong>10</strong> feet tall and has a shadow that is <strong>5</strong> feet long. At the same time, the shadow of the other tree is <strong>2</strong> feet long. How tall, in feet, is the other tree?",
choices: [
{ label: "A", text: "<strong>3</strong>" },
{ label: "B", text: "<strong>4</strong>" },
{ label: "C", text: "<strong>8</strong>" },
{ label: "D", text: "<strong>27</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Each tree and its shadow can be modeled using a right triangle, where the height of the tree and the length of its shadow are the legs of the triangle. At a given point in time, the right triangles formed by two nearby trees and their respective shadows will be similar. Therefore, if the height of the other tree is <strong>x</strong>, in feet, the value of <strong>x</strong> can be calculated by solving the proportional relationship <strong>(10 feet tall) / (5 feet long) = (x feet tall) / (2 feet long)</strong>. This equation is equivalent to<strong>(10) / (5) = (x) / (2)</strong>, or <strong>2 = (x) / (2)</strong>. Multiplying each side of the equation <strong>2 = (x) / (2)</strong> by <strong>2</strong> yields <strong>4 = x</strong>. Therefore, the other tree is <strong>4 feet</strong> tall.<br>Choice A is incorrect and may result from calculating the difference between the lengths of the shadows, rather than the height of the other tree.<br>Choice C is incorrect and may result from calculating the difference between the height of the <strong>10</strong>-foot-tall tree and the length of the shadow of the other tree, rather than calculating the height of the other tree.<br>Choice D is incorrect and may result from a conceptual or calculation error.",
hasFigure: false,
},
{
id: "a4c05a1b",
type: "mcq",
questionHtml:
"Clockwise from top left, the 3 lines are labeled m, r, and s.<br>Line m intersects both line r and line s.<br>At the intersection of line m and line r, 1 angle is labeled clockwise from top left as follows:<br><br>Top right: x°<br><br>At the intersection of line m and line s, 1 angle is labeled clockwise from top left as follows:<br><br>Bottom right: y°<br><br>A note indicates the figure is not drawn to scale.<br><br>In the figure shown, lines <strong>r</strong> and <strong>s</strong> are parallel, and line <strong>m</strong> intersects both lines. If <strong>y < 65</strong>, which of the following must be true?",
choices: [
{ label: "A", text: "<strong>x < 115</strong>" },
{ label: "B", text: "<strong>x > 115</strong>" },
{ label: "C", text: "<strong>x + y < 180</strong>" },
{ label: "D", text: "<strong>x + y > 180</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. In the figure shown, the angle measuring <strong>y °</strong> is congruent to its vertical angle formed by lines <strong>s</strong> and <strong>m</strong>, so the measure of the vertical angle is also <strong>y °</strong>. The vertical angle forms a same-side interior angle pair with the angle measuring <strong>x °</strong>. It's given that lines <strong>r</strong> and <strong>s</strong> are parallel. Therefore, same-side interior angles in the figure are supplementary, which means the sum of the measure of the vertical angle and the measure of the angle measuring <strong>x °</strong> is <strong>180 °</strong>, or <strong>x + y = 180</strong>. Subtracting <strong>x</strong> from both sides of this equation yields <strong>y = 180 x</strong>. Substituting <strong>180 x</strong> for <strong>y</strong> in the inequality <strong>y < 65</strong> yields <strong>180 x < 65</strong>. Adding <strong>x</strong> to both sides of this inequality yields <strong>180 < 65 + x</strong>. Subtracting <strong>65</strong> from both sides of this inequality yields <strong>115 < x</strong>, or <strong>x > 115</strong>. Thus, if <strong>y < 65</strong>, it must be true that <strong>x > 115</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect. <strong>x + y</strong> must be equal to, not less than, <strong>180</strong>.<br>Choice D is incorrect. <strong>x + y</strong> must be equal to, not greater than, <strong>180</strong>.",
hasFigure: true,
figureUrl: "/practice-images/a4c05a1b_svg1.svg",
},
{
id: "c7bed21d",
type: "mcq",
questionHtml:
"Quadrilateral <strong>P prime Q prime R prime S prime</strong> is similar to quadrilateral <strong>P Q R S</strong>, where <strong>P</strong>, <strong>Q</strong>, <strong>R</strong>, and <strong>S</strong> correspond to <strong>P prime</strong>, <strong>Q prime</strong>, <strong>R prime</strong>, and <strong>S prime</strong>, respectively. The measure of angle <strong>P</strong> is <strong>30 °</strong>, the measure of angle <strong>Q</strong> is <strong>50 °</strong>, and the measure of angle <strong>R</strong> is <strong>70 °</strong>. The length of each side of <strong>P prime Q prime R prime S prime</strong> is <strong>3</strong> times the length of each corresponding side of <strong>P Q R S</strong>. What is the measure of angle <strong>P prime</strong>?",
choices: [
{ label: "A", text: "<strong>10 °</strong>" },
{ label: "B", text: "<strong>30 °</strong>" },
{ label: "C", text: "<strong>40 °</strong>" },
{ label: "D", text: "<strong>90 °</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. It's given that quadrilateral <strong>P prime Q prime R prime S prime</strong> is similar to quadrilateral <strong>P Q R S</strong>, where <strong>P</strong>, <strong>Q</strong>, <strong>R</strong>, and <strong>S</strong> correspond to <strong>P prime</strong>, <strong>Q prime</strong>, <strong>R prime</strong>, and <strong>S prime</strong>, respectively. Since corresponding angles of similar quadrilaterals are congruent, it follows that the measure of angle <strong>P</strong> is equal to the measure of angle <strong>P prime</strong>. It's given that the measure of angle <strong>P</strong> is <strong>30 °</strong>. Therefore, the measure of angle <strong>P prime</strong> is <strong>30 °</strong>.<br>Choice A is incorrect. This is <strong>one third</strong> the measure of angle <strong>P prime</strong>.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect. This is <strong>3</strong> times the measure of angle <strong>P prime</strong>.",
hasFigure: false,
},
{
id: "d3fe472f",
type: "mcq",
questionHtml:
"Triangle <strong>A B C</strong> is similar to triangle <strong>X Y Z</strong>, such that <strong>A</strong>, <strong>B</strong>, and <strong>C</strong> correspond to <strong>X</strong>, <strong>Y</strong>, and <strong>Z</strong> respectively. The length of each side of triangle <strong>X Y Z</strong> is <strong>2</strong> times the length of its corresponding side in triangle <strong>A B C</strong>. The measure of side <strong>A B</strong> is <strong>16</strong>. What is the measure of side <strong>X Y</strong>?",
choices: [
{ label: "A", text: "<strong>14</strong>" },
{ label: "B", text: "<strong>16</strong>" },
{ label: "C", text: "<strong>18</strong>" },
{ label: "D", text: "<strong>32</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. It's given that triangle <strong>A B C</strong> is similar to triangle <strong>X Y Z</strong>, such that <strong>A</strong>, <strong>B</strong>, and <strong>C</strong> correspond to <strong>X</strong>, <strong>Y</strong>, and <strong>Z</strong>, respectively. Therefore, side <strong>A B</strong> corresponds to side <strong>X Y</strong>. Since the length of each side of triangle <strong>X Y Z</strong> is <strong>2</strong> times the length of its corresponding side in triangle <strong>A B C</strong>, it follows that the measure of side <strong>X Y</strong> is <strong>2</strong> times the measure of side <strong>A B</strong>. Thus, since the measure of side <strong>A B</strong> is <strong>16</strong>, then the measure of side <strong>X Y</strong> is <strong>2 (16)</strong>, or <strong>32</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect. This is the measure of side <strong>A B</strong>, not side <strong>X Y</strong>.<br>Choice C is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "fd8745fc",
type: "spr",
questionHtml:
"In triangle <strong>J K L</strong>, the measures of <strong>angle K</strong> and <strong>angle L</strong> are each <strong>48 °</strong>. What is the measure of <strong>angle J</strong>, in degrees? (Disregard the degree symbol when entering your answer.)",
choices: [],
correctAnswer: "84",
explanation:
"The correct answer is <strong>84</strong>. The sum of the measures of the interior angles of a triangle is <strong>180 °</strong>. It's given that in triangle <strong>J K L</strong>, the measures of <strong>angle K</strong>and <strong>angle L</strong> are each <strong>48 °</strong>. Adding the measures, in degrees, of <strong>angle K</strong> and <strong>angle L</strong> gives <strong>48 + 48</strong>, or <strong>96</strong>. Therefore, the measure of <strong>angle J</strong>, in degrees, is <strong>180 96</strong>, or <strong>84</strong>.",
hasFigure: false,
},
];
export const LINES_ANGLES_HARD: PracticeQuestion[] = [
{
id: "17912810",
type: "spr",
questionHtml:
"Counterclockwise from top right, the lines are labeled s, r, q, and t.<br>Line s intersects line r above line q.<br>Line s and line r each intersect line q and line t.<br>At the intersection of line s and line r, 1 angle is labeled counterclockwise from top as follows:<br><br>Top: a°<br><br>At the intersection of line s and line q, 1 angle is labeled counterclockwise from top-left as follows:<br><br>Top left: b°<br><br>At the intersection of line r and line t:<br><br>The line segment divides the bottom-left angle into two equal angles, each labeled w°.<br><br>A note indicates the figure is not drawn to scale.<br><br>In the figure, parallel lines <strong>q</strong> and <strong>t</strong> are intersected by lines <strong>r</strong> and <strong>s</strong>. If <strong>a = 43</strong> and <strong>b = 122</strong>, what is the value of <strong>w</strong>?",
choices: [],
correctAnswer: "101/2, 50.5",
explanation:
"The correct answer is <strong>(101) / (2)</strong>. In the figure, lines <strong>q</strong>, <strong>r</strong>, and <strong>s</strong> form a triangle. One interior angle of this triangle is vertical to the angle marked <strong>a °</strong>; therefore, the interior angle also has measure <strong>a °</strong>. It's given that <strong>a = 43</strong>. Therefore, the interior angle of the triangle has measure <strong>43 °</strong>. A second interior angle of the triangle forms a straight line, <strong>q</strong>, with the angle marked <strong>b °</strong>. Therefore, the sum of the measures of these two angles is <strong>180 °</strong>. It's given that <strong>b = 122</strong>. Therefore, the angle marked <strong>b °</strong> has measure <strong>122 °</strong> and the second interior angle of the triangle has measure <strong>(180 122) °</strong>, or <strong>58 °</strong>. The sum of the interior angles of a triangle is <strong>180 °</strong>. Therefore, the measure of the third interior angle of the triangle is <strong>(180 43 58) °</strong>, or <strong>79 °</strong>. It's given that parallel lines <strong>q</strong> and <strong>t</strong> are intersected by line <strong>r</strong>. It follows that the triangle's interior angle with measure <strong>79 °</strong> is congruent to the same side interior angle between lines <strong>q</strong> and <strong>t</strong> formed by lines <strong>t</strong> and <strong>r</strong>. Since this angle is supplementary to the two angles marked <strong>w °</strong>, the sum of <strong>79 °</strong>, <strong>w °</strong>, and <strong>w °</strong> is <strong>180 °</strong>. It follows that <strong>79 + w + w = 180</strong>, or <strong>79 + 2 w = 180</strong>. Subtracting <strong>79</strong> from both sides of this equation yields <strong>2 w = 101</strong>. Dividing both sides of this equation by <strong>2</strong> yields <strong>w = (101) / (2)</strong>. Note that 101/2 and 50.5 are examples of ways to enter a correct answer.",
hasFigure: true,
figureUrl: "/practice-images/17912810_svg1.svg",
},
{
id: "3b225698",
type: "mcq",
questionHtml:
"Triangle <strong>X Y Z</strong> is similar to triangle <strong>R S T</strong> such that <strong>X</strong>, <strong>Y</strong>, and <strong>Z</strong> correspond to <strong>R</strong>, <strong>S</strong>, and <strong>T</strong>, respectively. The measure of <strong>angle Z</strong> is <strong>20 °</strong> and <strong>2 X Y = R S</strong>. What is the measure of <strong>angle T</strong>?",
choices: [
{ label: "A", text: "<strong>2 °</strong>" },
{ label: "B", text: "<strong>10 °</strong>" },
{ label: "C", text: "<strong>20 °</strong>" },
{ label: "D", text: "<strong>40 °</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that triangle <strong>X Y Z</strong> is similar to triangle <strong>R S T</strong>, such that <strong>X</strong>, <strong>Y</strong>, and <strong>Z</strong> correspond to <strong>R</strong>, <strong>S</strong>, and <strong>T</strong>, respectively. Since corresponding angles of similar triangles are congruent, it follows that the measure of <strong>angle Z</strong> is congruent to the measure of <strong>angle T</strong>. Its given that the measure of <strong>angle Z</strong> is <strong>20 °</strong>. Therefore, the measure of <strong>angle T</strong> is <strong>20 °</strong>.<br>Choice A is incorrect and may result from a conceptual error.<br>Choice B is incorrect. This is half the measure of <strong>angle Z</strong>.<br>Choice D is incorrect. This is twice the measure of <strong>angle Z</strong>.",
hasFigure: false,
},
{
id: "5b4757df",
type: "spr",
questionHtml:
"In triangle <strong>R S T</strong>, angle <strong>T</strong> is a right angle, point <strong>L</strong> lies on <strong>R S</strong>, point <strong>K</strong> lies on <strong>S T</strong>, and <strong>L K</strong> is parallel to <strong>R T</strong>. If the length of <strong>R T</strong> is <strong>72</strong> units, the length of <strong>L K</strong> is <strong>24</strong> units, and the area of triangle <strong>R S T</strong> is <strong>792</strong> square units, what is the length of <strong>K T</strong>, in units?",
choices: [],
correctAnswer: "14.66, 14.67, 44/3",
explanation:
"The correct answer is <strong>(44) / (3)</strong>. It's given that in triangle <strong>R S T</strong>, angle <strong>T</strong> is a right angle. The area of a right triangle can be found using the formula <strong>A = one half script l 1 script l 2</strong>, where <strong>A</strong> represents the area of the right triangle, <strong>script l 1</strong> represents the length of one leg of the triangle, and <strong>script l 2</strong> represents the length of the other leg of the triangle. In triangle <strong>R S T</strong>, the two legs are <strong>R T</strong> and <strong>S T</strong>. Therefore, if the length of <strong>R T</strong> is <strong>72</strong> and the area of triangle <strong>R S T</strong> is <strong>792</strong>, then <strong>792 = one half (72) (S T)</strong>, or <strong>792 = (36) (S T)</strong>. Dividing both sides of this equation by <strong>36</strong> yields <strong>22 = S T</strong>. Therefore, the length of <strong>S T</strong> is <strong>22</strong>. It's also given that point <strong>L</strong> lies on <strong>R S</strong>, point <strong>K</strong> lies on <strong>S T</strong>, and <strong>L K</strong> is parallel to <strong>R T</strong>. It follows that angle <strong>L K S</strong> is a right angle. Since triangles <strong>R S T</strong> and <strong>L S K</strong> share angle <strong>S</strong> and have right angles <strong>T</strong> and <strong>K</strong>, respectively, triangles <strong>R S T</strong> and <strong>L S K</strong> are similar triangles. Therefore, the ratio of the length of <strong>R T</strong> to the length of <strong>L K</strong> is equal to the ratio of the length of <strong>S T</strong> to the length of <strong>S K</strong>. If the length of <strong>R T</strong> is <strong>72</strong> and the length of <strong>L K</strong> is <strong>24</strong>, it follows that the ratio of the length of <strong>R T</strong> to the length of <strong>L K</strong> is <strong>(72) / (24)</strong>, or <strong>3</strong>, so the ratio of the length of <strong>S T</strong> to the length of <strong>S K</strong> is <strong>3</strong>. Therefore, <strong>(22) / (S K) = 3</strong>. Multiplying both sides of this equation by <strong>S K</strong> yields <strong>22 = (3) (S K)</strong>. Dividing both sides of this equation by <strong>3</strong> yields <strong>(22) / (3) = S K</strong>. Since the length of <strong>S T</strong>, <strong>22</strong>, is the sum of the length of <strong>S K</strong>, <strong>(22) / (3)</strong>, and the length of <strong>K T</strong>, it follows that the length of <strong>K T</strong> is <strong>22 (22) / (3)</strong>, or <strong>(44) / (3)</strong>. Note that 44/3, 14.66, and 14.67 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "6a3fbec3",
type: "spr",
questionHtml:
"In the figure above, <br> <strong>the length of B D = 6</strong> and <br> <strong>the length of A D = 8</strong>. What is the length of <br> <strong>D C</strong> ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 4.5. According to the properties of right triangles, BD divides triangle ABC into two similar triangles, ABD and BCD. The corresponding sides of ABD and BCD are proportional, so the ratio of BD to AD is the same as the ratio of DC to BD. Expressing this information as a proportion gives <strong>six eighths = the fraction D C, over 6</strong>. Solving the proportion for DC results in <br> <strong>D C = 4 . 5</strong>. Note that 4.5 and 9/2 are examples of ways to enter a correct answer.",
hasFigure: true,
figureUrl: "/practice-images/6a3fbec3_img1.png",
},
{
id: "6d99b141",
type: "spr",
questionHtml:
"Triangle upper A upper C upper D partially overlaps triangle upper E upper B upper D.<br>Point upper C is on line segment upper B upper D.<br>Point upper E is on line segment upper A upper D.<br>The measure of angle upper A upper E upper B is x°.<br>A note indicates the figure is not drawn to scale.<br><br> <br>In the figure, <strong>A C = C D</strong>. The measure of angle <strong>E B C</strong> is <strong>45 °</strong>, and the measure of angle <strong>A C D</strong> is <strong>104 °</strong>. What is the value of <strong>x</strong>?",
choices: [],
correctAnswer: "83",
explanation:
"The correct answer is <strong>83</strong>. It's given that in the figure, <strong>A C = C D</strong>. Thus, triangle <strong>A C D</strong> is an isosceles triangle and the measure of angle <strong>C D A</strong> is equal to the measure of angle <strong>C A D</strong>. The sum of the measures of the interior angles of a triangle is <strong>180 °</strong>. Thus, the sum of the measures of the interior angles of triangle <strong>A C D</strong> is <strong>180 °</strong>. It's given that the measure of angle <strong>A C D</strong> is <strong>104 °</strong>. It follows that the sum of the measures of angles <strong>C D A</strong> and <strong>C A D</strong> is <strong>(180 104) °</strong>, or <strong>76 °</strong>. Since the measure of angle <strong>C D A</strong> is equal to the measure of angle <strong>C A D</strong>, the measure of angle <strong>C D A</strong> is half of <strong>76 °</strong>, or <strong>38 °</strong>. The sum of the measures of the interior angles of triangle <strong>B D E</strong> is <strong>180 °</strong>. It's given that the measure of angle <strong>E B C</strong> is <strong>45 °</strong>. Since the measure of angle <strong>B D E</strong>, which is the same angle as angle <strong>C D A</strong>, is <strong>38 °</strong>, it follows that the measure of angle <strong>D E B</strong> is <strong>(180 45 38) °</strong>, or <strong>97 °</strong>. Since angle <strong>D E B</strong> and angle <strong>A E B</strong> form a straight line, the sum of the measures of these angles is <strong>180 °</strong>. It's given in the figure that the measure of angle <strong>A E B</strong> is <strong>x °</strong>. It follows that <strong>97 + x = 180</strong>. Subtracting <strong>97</strong> from both sides of this equation yields <strong>x = 83</strong>.",
hasFigure: true,
figureUrl: "/practice-images/6d99b141_svg1.svg",
},
{
id: "740bf79f",
type: "mcq",
questionHtml:
"In the figure above, what is the length of <strong>NQ</strong> ?",
choices: [
{ label: "A", text: "2.2" },
{ label: "B", text: "2.3" },
{ label: "C", text: "2.4" },
{ label: "D", text: "2.5" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. First, <strong>M P</strong> is the hypotenuse of right <strong>triangle M N P</strong>, whose legs have lengths 3 and 4. Therefore, <strong>(the length of M P, ), ² = 3² + 4²</strong>, so <strong>(the length of M P, ), ² = 25</strong> and <strong>the length of M P = 5</strong>. Second, because <strong>angle M N P</strong> corresponds to <strong>angle N Q P</strong> and because <strong>angle M P N</strong> corresponds to <strong>angle N P Q</strong>, <strong>triangle M N P</strong> is similar to <strong>triangle N Q P</strong>. The ratio of corresponding sides of similar triangles is constant, so <strong>the length of N Q over the length of M N = the length of N P over the length of M P</strong>. Since <strong>M P = 5</strong> and its given that <strong>the length of M N = 3</strong> and <strong>the length of N P = 4</strong>, <strong>the length of N Q, over 3 = 4 over 5</strong>. Solving for NQ results in <strong>the length of N Q = 12 over 5</strong>, or 2.4.Choices A, B, and D are incorrect and may result from setting up incorrect ratios.",
hasFigure: true,
figureUrl: "/practice-images/740bf79f_img1.png",
},
{
id: "901c3215",
type: "mcq",
questionHtml:
"In triangles <strong>A B C</strong> and <strong>D E F</strong>, angles <strong>B</strong> and <strong>E</strong> each have measure <strong>27 °</strong> and angles <strong>C</strong> and <strong>F</strong> each have measure <strong>41 °</strong>. Which additional piece of information is sufficient to determine whether triangle <strong>A B C</strong> is congruent to triangle <strong>D E F</strong>?",
choices: [
{ label: "A", text: "The measure of angle <strong>A</strong>" },
{ label: "B", text: "The length of side <strong>A B</strong>" },
{
label: "C",
text: "The lengths of sides <strong>B C</strong> and <strong>E F</strong>",
},
{ label: "D", text: "No additional information is necessary." },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Since angles <strong>B</strong> and <strong>E</strong> each have the same measure and angles <strong>C</strong> and <strong>F</strong> each have the same measure, triangles <strong>A B C</strong> and <strong>D E F</strong> are similar, where side <strong>B C</strong> corresponds to side <strong>E F</strong>. To determine whether two similar triangles are congruent, it is sufficient to determine whether one pair of corresponding sides are congruent. Therefore, to determine whether triangles <strong>A B C</strong> and <strong>D E F</strong> are congruent, it is sufficient to determine whether sides <strong>B C</strong> and <strong>E F</strong> have equal length. Thus, the lengths of <strong>B C</strong> and <strong>E F</strong> are sufficient to determine whether triangle <strong>A B C</strong> is congruent to triangle <strong>D E F</strong>.<br>Choice A is incorrect and may result from conceptual errors.<br>Choice B is incorrect and may result from conceptual errors.<br>Choice D is incorrect. The given information is sufficient to determine that triangles <strong>A B C</strong> and <strong>D E F</strong> are similar, but not whether they are congruent.",
hasFigure: false,
},
{
id: "947a3cde",
type: "spr",
questionHtml:
"In the figure above, <strong>M Q</strong> and <strong>N R</strong> intersect at point P, <strong>N P = Q P</strong>, and <strong>M P = P R</strong>. What is the measure, in degrees, of <strong>angle Q M R</strong> ? (Disregard the degree symbol when gridding your answer.)",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 30. It is given that the measure of <strong>angle Q P R</strong> is <strong>60 °</strong>. Angle MPR and <strong>angle Q P R</strong> are collinear and therefore are supplementary angles. This means that the sum of the two angle measures is <strong>180 °</strong>, and so the measure of <strong>angle M P R</strong> is <strong>120 °</strong>. The sum of the angles in a triangle is <strong>180 °</strong>. Subtracting the measure of <strong>angle M P R</strong> from <strong>180 °</strong> yields the sum of the other angles in the triangle MPR. Since <strong>180 120 = 60</strong>, the sum of the measures of <strong>angle Q M R</strong> and <strong>angle N R M</strong> is <strong>60 °</strong>. It is given that <strong>the length of side M P = the length of side P R</strong>, so it follows that triangle MPR is isosceles. Therefore<strong>angle Q M R</strong> and <strong>angle N R M</strong> must be congruent. Since the sum of the measure of these two angles is <strong>60 °</strong>, it follows that the measure of each angle is <strong>30 °</strong>.An alternate approach would be to use the exterior angle theorem, noting that the measure of <strong>angle Q P R</strong> is equal to the sum of the measures of <strong>angle Q M R</strong> and <strong>angle N R M</strong>. Since both angles are equal, each of them has a measure of <strong>30 °</strong>.",
hasFigure: true,
figureUrl: "/practice-images/947a3cde_img1.png",
},
{
id: "a0369739",
type: "mcq",
questionHtml:
"In triangle <strong>A B C</strong>, the measure of angle <strong>B</strong> is <strong>90 °</strong> and <strong>B D</strong> is an altitude of the triangle. The length of <strong>A B</strong> is <strong>15</strong> and the length of <strong>A C</strong> is <strong>23</strong> greater than the length of <strong>A B</strong>. What is the value of <strong>(B C) / (B D)</strong>?",
choices: [
{ label: "A", text: "<strong>(15) / (38)</strong>" },
{ label: "B", text: "<strong>(15) / (23)</strong>" },
{ label: "C", text: "<strong>(23) / (15)</strong>" },
{ label: "D", text: "<strong>(38) / (15)</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. It's given that in triangle <strong>A B C</strong>, the measure of angle <strong>B</strong> is <strong>90 °</strong> and  <strong>B D</strong> is an altitude of the triangle. Therefore, the measure of angle <strong>B D C</strong> is <strong>90 °</strong>. It follows that angle <strong>B</strong> is congruent to angle <strong>D</strong> and angle <strong>C</strong> is congruent to angle <strong>C</strong>. By the angle-angle similarity postulate, triangle <strong>A B C</strong> is similar to triangle <strong>B D C</strong>. Since triangles <strong>A B C</strong> and <strong>B D C</strong> are similar, it follows that <strong>(A C) / (A B) = (B C) / (B D)</strong>. It's also given that the length of <strong>A B</strong> is <strong>15</strong> and the length of <strong>A C</strong> is <strong>23</strong> greater than the length of <strong>A B</strong>. Therefore, the length of <strong>A C</strong> is <strong>15 + 23</strong>, or <strong>38</strong>. Substituting <strong>15</strong> for <strong>A B</strong> and <strong>38</strong> for <strong>A C</strong> in the equation <strong>(A C) / (A B) = (B C) / (B D)</strong> yields <strong>(38) / (15) = (B C) / (B D)</strong>. Therefore, the value of <strong>(B C) / (B D)</strong> is <strong>(38) / (15)</strong>.<br>Choice A is incorrect. This is the value of <strong>(B D) / (B C)</strong>.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "bd7f6e30",
type: "mcq",
questionHtml:
"In the figure above, <strong>R T = T U</strong>. What is the value of x ?",
choices: [
{ label: "A", text: "72" },
{ label: "B", text: "66" },
{ label: "C", text: "64" },
{ label: "D", text: "58" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Since <strong>the length of side R T = the length of side T U</strong>, it follows that <strong>triangle R T U</strong> is an isosceles triangle with base RU. Therefore, <strong>angle T R U</strong> and <strong>angle T U R</strong> are the base angles of an isosceles triangle and are congruent. Let the measures of both <strong>angle T R U</strong> and <strong>angle T U R</strong> be <strong>t °</strong>. According to the triangle sum theorem, the sum of the measures of the three angles of a triangle is <strong>180 °</strong>. Therefore, <strong>114 ° + 2 t ° = 180 °</strong>, so <strong>t = 33</strong>.Note that <strong>angle T U R</strong> is the same angle as <strong>angle S U V</strong>. Thus, the measure of <strong>angle S U V</strong> is <strong>33 °</strong>. According to the triangle exterior angle theorem, an external angle of a triangle is equal to the sum of the opposite interior angles. Therefore, <strong>x °</strong> is equal to the sum of the measures of <strong>angle V S U</strong> and <strong>angle S U V</strong>; that is, <strong>31 ° + 33 ° = 64 °</strong>. Thus, the value of x is 64.<br>Choice B is incorrect. This is the measure of <strong>angle S T R</strong>, but <strong>angle S T R</strong> is not congruent to <strong>angle S V R</strong>. Choices A and D are incorrect and may result from a calculation error.",
hasFigure: true,
figureUrl: "/practice-images/bd7f6e30_img1.png",
},
{
id: "e10d8313",
type: "spr",
questionHtml:
"From left to right, horizontal line segment upper P upper V includes the following points:<br><br>Upper P<br>Upper Q<br>Upper R<br>Upper S<br>Upper T<br>Upper V<br><br>Points upper X and upper U are each below line segment upper P upper V.<br>From left to right, the following 2 overlapping triangles are formed between points on line segment upper P upper V and points upper X and upper U:<br><br>Triangle upper Q upper X upper S<br>Triangle upper R upper U upper T<br><br>Line segments upper R upper U and upper S upper X intersect at point upper W.<br>A note indicates the figure is not drawn to scale.<br><br>In the figure shown, points <strong>Q</strong>, <strong>R</strong>, <strong>S</strong>, and <strong>T</strong> lie on line segment <strong>P V</strong>, and line segment <strong>R U</strong> intersects line segment <strong>S X</strong> at point <strong>W</strong>. The measure of <strong>angle S Q X</strong> is <strong>48 °</strong>, the measure of <strong>angle S X Q</strong> is <strong>86 °</strong>, the measure of <strong>angle S W U</strong> is <strong>85 °</strong>, and the measure of <strong>angle V T U</strong> is <strong>162 °</strong>. What is the measure, in degrees, of <strong>angle T U R</strong>?",
choices: [],
correctAnswer: "123",
explanation:
"The correct answer is <strong>123</strong>. The triangle angle sum theorem states that the sum of the measures of the interior angles of a triangle is <strong>180</strong> degrees. It's given that the measure of <strong>angle S Q X</strong> is <strong>48 °</strong> and the measure of <strong>angle S X Q</strong> is <strong>86 °</strong>. Since points <strong>S</strong>, <strong>Q</strong>, and <strong>X</strong> form a triangle, it follows from the triangle angle sum theorem that the measure, in degrees, of <strong>angle Q S X</strong> is <strong>180 48 86</strong>, or <strong>46</strong>. It's also given that the measure of <strong>angle S W U</strong> is <strong>85 °</strong>. Since <strong>angle S W U</strong> and <strong>angle S W R</strong> are supplementary angles, the sum of their measures is <strong>180</strong> degrees. It follows that the measure, in degrees, of <strong>angle S W R</strong> is <strong>180 85</strong>, or <strong>95</strong>. Since points <strong>R</strong>, <strong>S</strong>, and <strong>W</strong> form a triangle, and <strong>angle R S W</strong> is the same angle as <strong>angle Q S X</strong>, it follows from the triangle angle sum theorem that the measure, in degrees, of <strong>angle W R S</strong> is <strong>180 46 95</strong>, or <strong>39</strong>. It's given that the measure of <strong>angle V T U</strong> is <strong>162 °</strong>. Since <strong>angle V T U</strong> and <strong>angle S T U</strong> are supplementary angles, the sum of their measures is <strong>180</strong> degrees. It follows that the measure, in degrees, of <strong>angle S T U</strong> is <strong>180 162</strong>, or <strong>18</strong>. Since points <strong>R</strong>, <strong>T</strong>, and <strong>U</strong> form a triangle, and <strong>angle U R T</strong> is the same angle as <strong>angle W R S</strong>, it follows from the triangle angle sum theorem that the measure, in degrees, of <strong>angle T U R</strong> is <strong>180 39 18</strong>, or <strong>123</strong>.",
hasFigure: true,
figureUrl: "/practice-images/e10d8313_svg1.svg",
},
{
id: "eeb4143c",
type: "spr",
questionHtml:
"The area of triangle ABC above is at least 48 but no more than 60. If y is an integer, what is one possible value of x ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is either <strong>the fraction 10 over 3</strong>, <strong>the fraction 15 over 4</strong>, or <strong>the fraction 25 over 6</strong>. The area of triangle ABC can be expressed as <strong>one half · (5 + 7, ) · y</strong> or <strong>6 y</strong>. Its given that the area of triangle ABC is at least 48 but no more than 60. It follows that <strong>48 ≤ 6 y, which ≤ 60</strong>. Dividing by 6 to isolate y in this compound inequality yields <strong>8 ≤ y, which ≤ 10</strong>. Since y is an integer, <strong>y = 8, 9, or 10</strong>. In the given figure, the two right triangles shown are similar because they have two pairs of congruent angles: their respective right angles and angle A. Therefore, the following proportion is true: <strong>the fraction x over y = the fraction 5 over 12</strong>. Substituting 8 for y in the proportion results in <strong>the fraction x over 8 = the fraction 5 over 12</strong>. Cross multiplying and solving for x yields <strong>the fraction 10 over 3</strong>. Substituting 9 for y in the proportion results in <strong>the fraction x over 9 = the fraction 5 over 12</strong>. Cross multiplying and solving for x yields <strong>the fraction 15 over 4</strong>. Substituting 10 for y in the proportion results in <strong>the fraction x over 10 = the fraction 5 over 12</strong>. Cross multiplying and solving for x yields <strong>the fraction 25 over 6</strong>. Note that 10/3, 15/4, 25/6, 3.333, 3.75, 4.166, and 4.167 are examples of ways to enter a correct answer.",
hasFigure: true,
figureUrl: "/practice-images/eeb4143c_img1.png",
},
{
id: "f7dbde16",
type: "mcq",
questionHtml:
"In triangles <strong>L M N</strong> and <strong>R S T</strong>, angles <strong>L</strong> and <strong>R</strong> each have measure <strong>60 °</strong>, <strong>L N = 10</strong>, and <strong>R T = 30</strong>. Which additional piece of information is sufficient to prove that triangle <strong>L M N</strong> is similar to triangle <strong>R S T</strong>?",
choices: [
{
label: "A",
text: "<strong>M N = 7</strong> and <strong>S T = 7</strong>",
},
{
label: "B",
text: "<strong>M N = 7</strong> and <strong>S T = 21</strong>",
},
{
label: "C",
text: "The measures of angles <strong>M</strong> and <strong>S</strong> are <strong>70 °</strong> and <strong>60 °</strong>, respectively.",
},
{
label: "D",
text: "The measures of angles <strong>M</strong> and <strong>T</strong> are <strong>70 °</strong> and <strong>50 °</strong>, respectively.",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. Two triangles are similar if they have three pairs of congruent corresponding angles. Its given that angles <strong>L</strong> and <strong>R</strong> each measure <strong>60 °</strong>, and so these corresponding angles are congruent. If angle <strong>M</strong> is <strong>70 °</strong>, then angle <strong>N</strong> must be <strong>50 °</strong> so that the sum of the angles in triangle <strong>L M N</strong> is <strong>180 °</strong>. If angle <strong>T</strong> is <strong>50 °</strong>, then angle <strong>S</strong> must be <strong>70 °</strong> so that the sum of the angles in triangle <strong>R S T</strong> is <strong>180 °</strong>. Therefore, if the measures of angles <strong>M</strong> and <strong>T</strong> are <strong>70 °</strong> and <strong>50 °</strong>, respectively, then corresponding angles <strong>M</strong> and <strong>S</strong> are both <strong>70 °</strong>, and corresponding angles <strong>N</strong> and <strong>T</strong> are both <strong>50 °</strong>. It follows that triangles <strong>L M N</strong> and <strong>R S T</strong> have three pairs of congruent corresponding angles, and so the triangles are similar. Therefore, the additional piece of information that is sufficient to prove that triangle <strong>L M N</strong> is similar to triangle <strong>R S T</strong> is that the measures of angles <strong>M</strong> and <strong>T</strong> are <strong>70 °</strong> and <strong>50 °</strong>, respectively.<br>Choice A is incorrect. If the measures of two sides in one triangle are proportional to the corresponding sides in another triangle and the included angles are congruent, then the triangles are similar. However, the two sides given are not proportional and the angle given is not included by the given sides.<br>Choice B is incorrect. If the measures of two sides in one triangle are proportional to the corresponding sides in another triangle and the included angles are congruent, then the triangles are similar. However, the angle given is not included between the proportional sides.<br>Choice C is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "f88f27e5",
type: "spr",
questionHtml: "What is the value of x ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 97. The intersecting lines form a triangle, and the angle with measure of <strong>x °</strong> is an exterior angle of this triangle. The measure of an exterior angle of a triangle is equal to the sum of the measures of the two nonadjacent interior angles of the triangle. One of these angles has measure of <strong>23 °</strong> and the other, which is supplementary to the angle with measure <strong>106 °</strong>, has measure of <strong>180 ° 106 ° = 74 °</strong>. Therefore, the value of x is <strong>23 + 74 = 97</strong>.",
hasFigure: true,
figureUrl: "/practice-images/f88f27e5_img1.png",
},
];

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,950 @@
import { type PracticeQuestion } from "../../types/lesson";
export const ONE_VAR_DATA_EASY: PracticeQuestion[] = [
{
id: "12dae628",
type: "mcq",
questionHtml:
"<strong>2</strong>, <strong>9</strong>, <strong>14</strong>, <strong>23</strong>, <strong>32</strong><br>What is the mean of the data shown?",
choices: [
{ label: "A", text: "<strong>14</strong>" },
{ label: "B", text: "<strong>16</strong>" },
{ label: "C", text: "<strong>17</strong>" },
{ label: "D", text: "<strong>32</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The mean of a set of data values is the sum of all the data values divided by the number of data values in the set. The sum of the data values shown is <strong>2 + 9 + 14 + 23 + 32</strong>, or <strong>80</strong>. Since there are <strong>5</strong> data values in the set, the mean of the data shown is <strong>(80) / (5)</strong>, or <strong>16</strong>.<br>Choice A is incorrect. This is the median, not the mean, of the data shown.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect. This is the maximum, not the mean, of the data shown.",
hasFigure: false,
},
{
id: "35bec412",
type: "spr",
questionHtml:
"<strong>73</strong>, <strong>74</strong>, <strong>75</strong>, <strong>77</strong>, <strong>79</strong>, <strong>82</strong>, <strong>84</strong>, <strong>85</strong>, <strong>91</strong><br>What is the median of the data shown?",
choices: [],
correctAnswer: "79",
explanation:
"The correct answer is <strong>79</strong>. The median of a data set with an odd number of values is the middle value of the set when the values are ordered from least to greatest. Because the given data set consists of nine values that are ordered from least to greatest, the median is the fifth value in the data set. Therefore, the median of the data shown is <strong>79</strong>.",
hasFigure: false,
},
{
id: "374b18f9",
type: "mcq",
questionHtml:
"The number of acres of useful timberland in 13 counties in California is summarized in the box plot above. Which of the following is closest to the median number of acres?",
choices: [
{ label: "A", text: "4,399" },
{ label: "B", text: "7,067" },
{ label: "C", text: "8,831" },
{ label: "D", text: "10,595" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The median of the data summarized by a box plot is the value associated with the vertical line segment within the box. According to the box plot shown, this value is slightly greater than 7,000. Therefore, the closest value for the median number of acres is 7,067.Choice A is incorrect. This is the value associated with the vertical line segment forming the left-hand side of the box. Choice C is incorrect. This value is greater than the value associated with the vertical line segment within the box. Choice D is incorrect. This is the value associated with the vertical line segment forming the right-hand side of the box.",
hasFigure: true,
figureUrl: "/practice-images/374b18f9_img1.png",
},
{
id: "4b09f783",
type: "spr",
questionHtml:
"A list of <strong>10</strong> data values is shown.<br><strong>6</strong>, <strong>8</strong>, <strong>16</strong>, <strong>4</strong>, <strong>17</strong>, <strong>26</strong>, <strong>8</strong>, <strong>5</strong>, <strong>5</strong>, <strong>5</strong><br>What is the mean of these data?",
choices: [],
correctAnswer: "10",
explanation:
"The correct answer is <strong>10</strong>. The mean of a data set is calculated by dividing the sum of the data values by the number of data values in the data set. For this data set, the mean can be calculated as <strong>(6 + 8 + 16 + 4 + 17 + 26 + 8 + 5 + 5 + 5) / (10)</strong>, which is equivalent to <strong>(100) / (10)</strong>, or <strong>10</strong>.",
hasFigure: false,
},
{
id: "4bb25495",
type: "mcq",
questionHtml:
"The table above shows the land area, in square kilometers, of the five smallest countries of the world in 2016. Based on the table, what is the mean land area of the 5 smallest countries in 2016, to the nearest square kilometer?",
choices: [
{ label: "A", text: "20" },
{ label: "B", text: "22" },
{ label: "C", text: "61" },
{ label: "D", text: "110" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The mean land area of these 5 countries is equal to the sum of the land areas of these countries, or <strong>2 . 0 + 21 + 61 + 26 + 0 . 4 4</strong>, divided by the number of countries in the table, 5, or <strong>the fraction with numerator 2 . 0 + 21 + 61 + 26 + 0 . 4 4, and denominator 5</strong>. Combining like terms in the numerator yields <strong>110 . 4 4 over 5</strong>, which simplifies to 22.088 square kilometers. This value, when rounded to the nearest square kilometer, is 22.Choice A is incorrect and may result from a calculation error. Choice C is incorrect. This is the greatest land area of the 5 countries in the table. Choice D is incorrect. This is the sum of the land areas of the 5 countries in the table, rounded to the nearest square kilometer.",
hasFigure: false,
},
{
id: "52f9a246",
type: "mcq",
questionHtml:
"<strong>4</strong>, <strong>4</strong>, <strong>4</strong>, <strong>4</strong>, <strong>8</strong>, <strong>8</strong>, <strong>8</strong>, <strong>13</strong>, <strong>13</strong><br>Which frequency table correctly represents the data listed?",
choices: [
{
label: "A",
text: "Number<br>Frequency<br><br><strong>4</strong><br><strong>4</strong><br><br><strong>8</strong><br><strong>3</strong><br><br><strong>13</strong><br><strong>2</strong>",
},
{
label: "B",
text: "Number<br>Frequency<br><br><strong>4</strong><br><strong>4</strong><br><br><strong>3</strong><br><strong>8</strong><br><br><strong>2</strong><br><strong>13</strong>",
},
{
label: "C",
text: "Number<br>Frequency<br><br><strong>4</strong><br><strong>16</strong><br><br><strong>8</strong><br><strong>24</strong><br><br><strong>13</strong><br><strong>26</strong>",
},
{
label: "D",
text: "Number<br>Frequency<br><br><strong>16</strong><br><strong>4</strong><br><br><strong>24</strong><br><strong>8</strong><br><br><strong>26</strong><br><strong>13</strong>",
},
],
correctAnswer: "A",
explanation:
"Choice A is correct. A frequency table is a table that lists the data value and shows the number of times the data value occurs. In the data listed, the number <strong>4</strong> occurs four times, the number <strong>8</strong> occurs three times, and the number <strong>13</strong> occurs two times. This corresponds to the table in choice A.<br>Choice B is incorrect. This table has the values for number and frequency reversed.<br>Choice C is incorrect because the frequency values don't represent the data listed.<br>Choice D is incorrect. This table represents the listed number values as the frequency values.",
hasFigure: false,
},
{
id: "55cfaf22",
type: "mcq",
questionHtml:
"Data set X: <strong>5</strong>, <strong>9</strong>, <strong>9</strong>, <strong>13</strong><br>Data set Y: <strong>5</strong>, <strong>9</strong>, <strong>9</strong>, <strong>13</strong>, <strong>27</strong><br>The lists give the values in data sets X and Y. Which statement correctly compares the mean of data set X and the mean of data set Y?",
choices: [
{
label: "A",
text: "The mean of data set X is greater than the mean of data set Y.",
},
{
label: "B",
text: "The mean of data set X is less than the mean of data set Y.",
},
{ label: "C", text: "The means of data set X and data set Y are equal." },
{
label: "D",
text: "There is not enough information to compare the means.",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. The mean of a data set is the sum of the values in the data set divided by the number of values in the data set. It follows that the mean of data set X is <strong>(5 + 9 + 9 + 13) / (4)</strong>, or <strong>9</strong>, and the mean of data set Y is <strong>(5 + 9 + 9 + 13 + 27) / (5)</strong>, or <strong>12.6</strong>. Since <strong>9</strong> is less than <strong>12.6</strong>, the mean of data set X is less than the mean of data set Y.<br>Alternate approach: Data set Y consists of the <strong>4</strong> values in data set X and one additional value, <strong>27</strong>. Since the additional value, <strong>27</strong>, is larger than any value in data set X, the mean of data set X is less than the mean of data set Y.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "57f45509",
type: "mcq",
questionHtml:
"From left to right the values of the vertical bars in the box plot are as follows:<br><br>First vertical bar: 2<br>Second vertical bar: 4<br>Third vertical bar: 5<br>Fourth vertical bar: 7<br>Fifth vertical bar: 8<br><br> <br>The box plot summarizes <strong>15</strong> data values. What is the median of this data set?",
choices: [
{ label: "A", text: "<strong>2</strong>" },
{ label: "B", text: "<strong>3</strong>" },
{ label: "C", text: "<strong>5</strong>" },
{ label: "D", text: "<strong>8</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The median of a data set represented in a box plot is given by the vertical line within the box. In the given box plot, the vertical line within the box occurs at <strong>5</strong>. Therefore, the median of this data set is <strong>5</strong>.<br>Choice A is incorrect. This is the minimum value of the data set.<br>Choice B is incorrect and may result from conceptual errors.<br>Choice D is incorrect. This is the maximum value of the data set.",
hasFigure: true,
figureUrl: "/practice-images/57f45509_svg1.svg",
},
{
id: "6670e407",
type: "mcq",
questionHtml:
"The table above shows the number of students from two different high schools who completed summer internships in each of five years. No student attended both schools. Which of the following statements are true about the number of students who completed summer internships for the 5 years shown?The mean number from Foothill High School is greater than the mean number from Valley High School.The median number from Foothill High School is greater than the median number from Valley High School.",
choices: [
{ label: "A", text: "I only" },
{ label: "B", text: "II only" },
{ label: "C", text: "I and II" },
{ label: "D", text: "Neither I nor II" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The mean of a data set is found by dividing the sum of the values by the number of values. Therefore, the mean number of students who completed summer internships from Foothill High School is <strong>the fraction with numerator 87 + 80 + 75 + 76 + 70, and denominator 5 = the fraction 388 over 5</strong>, or 77.6. Similarly, the mean number from Valley High School is <strong>the fraction with numerator 44 + 54 + 65 + 76 + 82, and denominator 5 = the fraction 321 over 5</strong>, or 64.2. Thus, the mean number from Foothill High School is greater than the mean number from Valley High School. When a data set has an odd number of elements, the median can be found by ordering the values from least to greatest and determining the value in the middle. Since there are five values in each data set, the third value in each ordered list is the median. Therefore, the median number from Foothill High School is 76 and the median number from Valley High School is 65. Thus, the median number from Foothill High School is greater than the median number from Valley High School.Choices A, B, and D are incorrect and may result from various misconceptions or miscalculations.",
hasFigure: false,
},
{
id: "66f03086",
type: "mcq",
questionHtml:
"<strong>71</strong>, <strong>72</strong>, <strong>73</strong>, <strong>76</strong>, <strong>77</strong>, <strong>79</strong>, <strong>83</strong>, <strong>87</strong>, <strong>93</strong><br>What is the median of the data shown?",
choices: [
{ label: "A", text: "<strong>71</strong>" },
{ label: "B", text: "<strong>77</strong>" },
{ label: "C", text: "<strong>78</strong>" },
{ label: "D", text: "<strong>79</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The median of a data set with an odd number of data values is defined as the middle value of the ordered list of values. The data set shown has nine values, so the median is the fifth value in the ordered list, which is <strong>77</strong>.<br>Choice A is incorrect. This is the minimum value of the data set, not the median.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect. This is the mean of the data set, not the median.",
hasFigure: false,
},
{
id: "708590d7",
type: "mcq",
questionHtml:
"Which of the following statements correctly compares the means of data set A and data set B?",
choices: [
{ label: "A", text: "The mean of each data set is 2." },
{ label: "B", text: "The mean of each data set is 4." },
{
label: "C",
text: "The mean of data set A is less than the mean of data set B.",
},
{
label: "D",
text: "The mean of data set A is greater than the mean of data set B.",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. The mean of a data set is found by dividing the sum of the values in the data set by the number of values in the data set. Therefore, the mean of data set A is <strong>the fraction with numerator 1 + 2 + 3 + 4 + 5 + 6 + 7, and denominator 7 = the fraction 28 over 7</strong>, or 4. The mean of data set B is <strong>the fraction with numerator 1 + 1 + 2 + 2 + 3 + 3 + 4, and denominator 7 = the fraction 16 over 7</strong>, or approximately 2.2857. Therefore, the mean of data set A is greater than the mean of data set B.Alternate approach: Data set A and data set B are both ordered from least to greatest value. Besides the first value in each data set, which is 1, each value in ordered data set B is less than the respective value in ordered data set A. Therefore, conceptually, the mean of data set A must be greater than the mean of data set B.<br>Choices A, B, and C are incorrect and may result from various misconceptions or miscalculations.",
hasFigure: false,
},
{
id: "7760c516",
type: "spr",
questionHtml:
"Each value in the data set shown represents the height, in centimeters, of a plant. <br><strong>6</strong>, <strong>10</strong>, <strong>13</strong>, <strong>2</strong>, <strong>15</strong>, <strong>22</strong>, <strong>10</strong>, <strong>4</strong>, <strong>4</strong>, <strong>4</strong><br>What is the mean height, in centimeters, of these plants?",
choices: [],
correctAnswer: "9",
explanation:
"The correct answer is <strong>9</strong>. The mean of a data set is the sum of the values in the data set divided by the number of values in the data set. It follows that the mean height, in centimeters, of these plants is the sum of the heights, in centimeters, of each plant, <strong>6 + 10 + 13 + 2 + 15 + 22 + 10 + 4 + 4 + 4</strong>, or <strong>90</strong>, divided by the number of plants in the data set, <strong>10</strong>. Therefore, the mean height, in centimeters, of these plants is <strong>(90) / (10)</strong>, or <strong>9</strong>.",
hasFigure: false,
},
{
id: "79340403",
type: "spr",
questionHtml:
"The data for the 10 categories are as follows:<br><br>Group 1: 30<br>Group 2: 62<br>Group 3: 36<br>Group 4: 50<br>Group 5: 46<br>Group 6: 40<br>Group 7: 54<br>Group 8: 60<br>Group 9: 16<br>Group 10: 20<br><br>The bar graph shows the distribution of <strong>414</strong> books collected by <strong>10</strong> different groups for a book drive. How many books were collected by group <strong>1</strong>?",
choices: [],
correctAnswer: "30",
explanation:
"The correct answer is <strong>30</strong>. The height of each bar in the bar graph shown represents the number of books collected by the group specified at the bottom of the bar. The bar for group <strong>1</strong> reaches a height of <strong>30</strong>. Therefore, group <strong>1</strong> collected <strong>30</strong> books.",
hasFigure: true,
figureUrl: "/practice-images/79340403_svg1.svg",
},
{
id: "820d7a73",
type: "spr",
questionHtml:
"The data for the 10 categories are as follows:<br><br>Group 1: 30<br>Group 2: 63<br>Group 3: 38<br>Group 4: 50<br>Group 5: 47<br>Group 6: 40<br>Group 7: 54<br>Group 8: 60<br>Group 9: 17<br>Group 10: 20<br><br>The bar graph shows the distribution of <strong>419</strong> cans collected by <strong>10</strong> different groups for a food drive. How many cans were collected by group <strong>6</strong>?",
choices: [],
correctAnswer: "40",
explanation:
"The correct answer is <strong>40</strong>. The height of each bar in the bar graph shown represents the number of cans collected by the group specified at the bottom of the bar. The bar for group <strong>6</strong> reaches a height of <strong>40</strong>. Therefore, group <strong>6</strong> collected <strong>40</strong> cans.",
hasFigure: true,
figureUrl: "/practice-images/820d7a73_svg1.svg",
},
{
id: "869a32f1",
type: "mcq",
questionHtml:
"Over this 5-day period, which of the following is NOT equal to 81°F?",
choices: [
{ label: "A", text: "Median of the high temperatures" },
{ label: "B", text: "Mean of the high temperatures" },
{ label: "C", text: "Mode of the high temperatures" },
{ label: "D", text: "Range of the high temperatures" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The range of a data set is the difference between the maximum and the minimum values in the set. The maximum value among the high temperatures in the table is 82°F and the minimum value is 80°F. Therefore, the range is 82°F 80°F = 2°F.Choice A is incorrect. The median of a data set is the middle value when the values in the set are ordered from least to greatest. Ordering the high temperatures this way gives the list 80, 81, 81, 81, 82. Therefore, the median high temperature is 81°F. Choice B is incorrect. The mean high temperature is <strong>the fraction with numerator 81 + 80 + 81 + 81 + 82, and denominator 5 = the fraction 405 over 5, which = 81</strong>. Choice C is incorrect. The mode is the value that occurs the greatest number of times. For the set of high temperatures shown, 81 is the value that occurs 3 times, and therefore, 81°F is the mode of the high temperatures.",
hasFigure: false,
},
{
id: "8736334b",
type: "mcq",
questionHtml:
"Data set A and data set B each contain 5 numbers. If the mean of data set A is equal to the mean of data set B, what is the value of x ?",
choices: [
{ label: "A", text: "77" },
{ label: "B", text: "85" },
{ label: "C", text: "86" },
{ label: "D", text: "95" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The mean of a data set is found by dividing the sum of the values in the data set by the number of values in the data set. Therefore, the mean of data set A is <strong>the fraction with numerator 72 + 73 + 73 + 76 + 76, and denominator 5</strong>, which simplifies to 74. The mean of data set B is represented by the equation <strong>the fraction with numerator 61 + 64 + 74 + 85 + x, and denominator 5</strong>, or <strong>the fraction with numerator 284 + x, and denominator 5</strong>. Its given that the mean of data set A is equal to the mean of data set B. Therefore, the equation <strong>74 = the fraction with numerator 284 + x, and denominator 5</strong> can be used to solve for x. Multiplying both sides of this equation by 5 yields <strong>370 = 284 + x</strong>. Subtracting 284 from both sides of this equation yields <strong>86 = x</strong>.Choices A, B, and D are incorrect and may result from calculation errors.",
hasFigure: false,
},
{
id: "93779b53",
type: "mcq",
questionHtml:
"The data for the 5 categories are as follows: <br><br>1: More than halfway above 25 students<br>2: Less than halfway above 30 students<br>3: More than halfway above 35 students<br>4: About halfway above 40 students<br>5: About halfway above 45 students<br><br>A group of students voted on five after-school activities. The bar graph shows the number of students who voted for each of the five activities. How many students chose activity <strong>3</strong>?",
choices: [
{ label: "A", text: "<strong>25</strong>" },
{ label: "B", text: "<strong>39</strong>" },
{ label: "C", text: "<strong>48</strong>" },
{ label: "D", text: "<strong>50</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The height of each bar in the bar graph given represents the number of students that voted for the activity specified at the bottom of the bar. The bar for activity <strong>3</strong> has a height that is between <strong>35</strong> and <strong>40</strong>. In other words, the number of students that chose activity <strong>3</strong> is between <strong>35</strong> students and <strong>40</strong> students. Of the given choices, <strong>39</strong> is the only value between <strong>35</strong> and <strong>40</strong>. Therefore, <strong>39</strong> students chose activity <strong>3</strong>.<br>Choice A is incorrect and may result from conceptual errors.<br>Choice C is incorrect. This is the number of students that chose activity <strong>5</strong>, not activity <strong>3</strong>.<br>Choice D is incorrect and may result from conceptual errors.",
hasFigure: true,
figureUrl: "/practice-images/93779b53_svg1.svg",
},
{
id: "a9647302",
type: "mcq",
questionHtml:
"<strong>The figure presents a bar graph titled “Results of Five Quality Control Trials.” The horizontal axis is labeled “Trial, ” and the following five letters are indicated along the axis: A, B, C, D, and E. Each letter has a vertical bar. The vertical axis is labeled “Number of defective light bulbs, ” and the numbers 0 through 8, in increments of 1, are indicated. The data represented by each of the 5 bars are as follows. Trial A, 4 light bulbs. Trial B, 7 light bulbs. Trial C, 1 light bulb. Trial D, 3 light bulbs. Trial E, 6 light bulbs.</strong>For quality control, a company that manufactures lightbulbs conducted five different trials. In each trial, 500 different lightbulbs were tested. The bar graph above shows the number of defective lightbulbs found in each trial. What is the mean number of defective lightbulbs for the five trials?",
choices: [
{ label: "A", text: "4.0" },
{ label: "B", text: "4.2" },
{ label: "C", text: "4.6" },
{ label: "D", text: "5.0" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The numbers of defective lightbulbs found for the five trials are 4, 7, 1, 3, and 6, respectively. The mean is therefore <strong>the fraction with numerator 4 + 7 + 1 + 3 + 6, and denominator 5 = 4 . 2</strong>.Choice A is incorrect. This is the median number of defective lightbulbs for the five trials. Choice C is incorrect and may result from an arithmetic error. Choice D is incorrect and may result from mistaking the number of trials for the number of defective lightbulbs.",
hasFigure: true,
figureUrl: "/practice-images/a9647302_img1.png",
},
{
id: "bfa8a85c",
type: "mcq",
questionHtml:
"<strong>6</strong>, <strong>6</strong>, <strong>8</strong>, <strong>8</strong>, <strong>8</strong>, <strong>10</strong>, <strong>21</strong><br>Which of the following lists represents a data set that has the same median as the data set shown?",
choices: [
{
label: "A",
text: "<strong>4</strong>, <strong>6</strong>, <strong>6</strong>, <strong>6</strong>, <strong>8</strong>, <strong>8</strong>",
},
{
label: "B",
text: "<strong>6</strong>, <strong>6</strong>, <strong>8</strong>, <strong>8</strong>, <strong>10</strong>, <strong>10</strong>",
},
{
label: "C",
text: "<strong>6</strong>, <strong>8</strong>, <strong>10</strong>, <strong>10</strong>, <strong>10</strong>, <strong>12</strong>",
},
{
label: "D",
text: "<strong>8</strong>, <strong>8</strong>, <strong>10</strong>, <strong>10</strong>, <strong>21</strong>, <strong>21</strong>",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. If a data set contains an odd number of data values, the median is represented by the middle data value in the list when the data values are listed in ascending or descending order. Since the data set shown has <strong>7</strong> data values and is in ascending order, it follows that the median is the fourth data value in the list, or <strong>8</strong>. If a data set contains an even number of data values, the median is between the two middle data values when the values are listed in ascending or descending order. Since each of the choices consists of a data set with <strong>6</strong> data values in ascending order, it follows that the median is between the third and fourth data value. The third and fourth data values in choice B are <strong>8</strong> and <strong>8</strong>. Thus, choice B represents a data set with a median of <strong>8</strong>. Since the median of the data set shown is <strong>8</strong> and choice B represents a data set with a median of <strong>8</strong>, it follows that choice B represents a data set that has the same median as the data set shown.<br>Choice A is incorrect. This list represents a data set with a median of <strong>6</strong>, not <strong>8</strong>.<br>Choice C is incorrect. This list represents a data set with a median of <strong>10</strong>, not <strong>8</strong>.<br>Choice D is incorrect. This list represents a data set with a median of <strong>10</strong>, not <strong>8</strong>.",
hasFigure: false,
},
{
id: "c54b92a2",
type: "mcq",
questionHtml:
"What is the range of the number of wheels made for the 11 one-hour periods?",
choices: [
{ label: "A", text: "5.5" },
{ label: "B", text: "5.0" },
{ label: "C", text: "4.5" },
{ label: "D", text: "4.0" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Range is defined as the difference between the greatest and least values from a set of data. The greatest number of wheels made during a one-hour period was 24 wheels. The least number of wheels was 19. Hence, the range is <strong>24 19 = 5</strong>, or 5.0.Choices A, C, and D are incorrect and may be the result of arithmetic errors or incorrectly identifying the greatest or least number of wheels made during a one-hour period.",
hasFigure: false,
},
{
id: "c88e0663",
type: "mcq",
questionHtml:
"For a school fund-raiser, 10 students sold a total of 90 boxes of cookies. Which of the following can be calculated from this information?",
choices: [
{ label: "A", text: "The average number of boxes sold per student" },
{ label: "B", text: "The median number of boxes sold per student" },
{ label: "C", text: "The greatest number of boxes sold by one student" },
{ label: "D", text: "The least number of boxes sold by one student" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The average can be found by dividing the total number of boxes sold by the number of students, which is <strong>the fraction 90 over 10 = 9</strong>.Choices B, C, and D are incorrect. Each results from choosing measures that require the results of individual students, which are not given.",
hasFigure: false,
},
{
id: "d1db8def",
type: "mcq",
questionHtml:
"Response<br>Frequency<br><br>Once a week or more<br><strong>3</strong><br><br>Two or three times a month<br><strong>16</strong><br><br>About once a month<br><strong>26</strong><br><br>A few times a year<br><strong>73</strong><br><br>Almost never<br><strong>53</strong><br><br>Never<br><strong>29</strong><br><br>Total<br><strong>200</strong><br><br>The table gives the results of a survey of <strong>200</strong> people who were asked how often they see a movie in a theater. How many people responded either “never” or “almost never”?",
choices: [
{ label: "A", text: "<strong>24</strong>" },
{ label: "B", text: "<strong>53</strong>" },
{ label: "C", text: "<strong>82</strong>" },
{ label: "D", text: "<strong>118</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The table gives the results of <strong>200</strong> people who were asked how often they see a movie in a theater. The table shows that <strong>29</strong> people responded “never” and <strong>53</strong> people responded “almost never.” Therefore, <strong>29 + 53</strong>, or <strong>82</strong>, people responded either “never” or “almost never.”<br>Choice A is incorrect. This is the difference between the number of people who responded “almost never” and the number of people who responded “never.”<br>Choice B is incorrect. This is the number of people who responded “almost never” but doesn't include those who responded “never.”<br>Choice D is incorrect. This is the number of people who responded something other than “never” or “almost never,” rather than the number of people who responded either “never” or “almost never.”",
hasFigure: false,
},
{
id: "f890dc20",
type: "mcq",
questionHtml: "What is the median of the seven data values shown?",
choices: [
{ label: "A", text: "2" },
{ label: "B", text: "3" },
{ label: "C", text: "4" },
{ label: "D", text: "9" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. When a data set has an odd number of values, the median can be found by ordering the values from least to greatest and determining the value in the middle. Since the values are already presented in order from least to greatest and there are 7 values, the median is the fourth value in the list. Therefore, the median is 3.Choice A is incorrect. This is the mode. Choice C is incorrect. This is the mean. Choice D is incorrect. This is the range.",
hasFigure: false,
},
{
id: "fa7a0164",
type: "mcq",
questionHtml:
"What was the mean low temperature, in degrees Fahrenheit, during the five-day period?",
choices: [
{ label: "A", text: "48.8" },
{ label: "B", text: "49" },
{ label: "C", text: "59" },
{ label: "D", text: "59.1" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The mean low temperature can be calculated by finding the sum of the low temperatures for all the days shown in the table, 49 + 37 + 41 + 54 + 63 = 244, and then dividing the sum by the number of days the temperature was recorded, <strong>244 ÷ 5 = 48 . 8</strong>.Choice B is incorrect. This may be the result of choosing the median rather than calculating the mean. Choices C and D are incorrect and may be the result of calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/fa7a0164_img1.png",
},
];
export const ONE_VAR_DATA_MEDIUM: PracticeQuestion[] = [
{
id: "07f2829b",
type: "spr",
questionHtml:
'<p><strong>International Tourist Arrivals, in millions</strong></p><table class="sat-table"><thead><tr><th>Country</th><th>2012</th><th>2013</th></tr></thead><tbody><tr><td>France</td><td>83.0</td><td>84.7</td></tr><tr><td>United States</td><td>66.7</td><td>69.8</td></tr><tr><td>Spain</td><td>57.5</td><td>60.7</td></tr><tr><td>China</td><td>57.7</td><td>55.7</td></tr><tr><td>Italy</td><td>46.4</td><td>47.7</td></tr><tr><td>Turkey</td><td>35.7</td><td>37.8</td></tr><tr><td>Germany</td><td>30.4</td><td>31.5</td></tr><tr><td>United Kingdom</td><td>26.3</td><td>32.2</td></tr><tr><td>Russia</td><td>24.7</td><td>28.4</td></tr></tbody></table><p>The table above shows the number of international tourist arrivals, rounded to the nearest tenth of a million, to the top nine tourist destinations in both 2012 and 2013. Based on the information given in the table, how much greater, in millions, was the median number of international tourist arrivals to the top nine tourist destinations in 2013 than the median number in 2012, to the nearest tenth of a million?</p>',
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 1.3. The median number of tourists is found by ordering the number of tourists from least to greatest and determining the middle value from this list. When the number of tourists in 2012 is ordered from least to greatest, the middle value, or the fifth number, is 46.4 million. When the number of tourists in 2013 is ordered from least to greatest, the middle value, or the fifth number, is 47.7 million. The difference between these two medians is <strong>47 . 7 million 46 . 4 million = 1 . 3 million</strong>. Note that 1.3 and 13/10 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "3f2ee20a",
type: "mcq",
questionHtml: "Which statement is true based on the table?",
choices: [
{
label: "A",
text: "The Group A data set was identical to the Group B data set.",
},
{ label: "B", text: "Group B contained the tallest participant." },
{
label: "C",
text: "The heights of the men in Group B had a larger spread than the heights of the men in Group A.",
},
{
label: "D",
text: "The median height of Group B is larger than the median height of Group A.",
},
],
correctAnswer: "C",
explanation:
"Choice C is correct. Standard deviation is a measure of spread, so data sets with larger standard deviations tend to have larger spread. The standard deviation of the heights of the men in Group B is larger than the standard deviation of the heights of the men in Group A. Therefore, the heights of the men in Group B had a larger spread than the heights of the men in Group A.Choice A is incorrect. If two data sets are identical, they will have equivalent means and equivalent standard deviations. Since the two data sets have different standard deviations, they cannot be identical. Choice B is incorrect. Without knowing the maximum value for each data set, its impossible to know which group contained the tallest participant. Choice D is incorrect. Since the means of the two groups are equivalent, the medians could also be the same or could be different, but it's impossible to tell from the given information.",
hasFigure: false,
},
{
id: "4c774b00",
type: "mcq",
questionHtml:
"The table above shows the distribution of ages of the 20 students enrolled in a college class. Which of the following gives the correct order of the mean, median, and mode of the ages?",
choices: [
{ label: "A", text: "mode < median < mean" },
{ label: "B", text: "mode < mean < median" },
{ label: "C", text: "median < mode < mean" },
{ label: "D", text: "mean < mode < median" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The mode is the data value with the highest frequency. So for the data shown, the mode is 18. The median is the middle data value when the data values are sorted from least to greatest. Since there are 20 ages ordered, the median is the average of the two middle values, the 10th and 11th, which for these data are both 19. Therefore, the median is 19. The mean is the sum of the data values divided by the number of the data values. So for these data, the mean is <strong>the fraction with numerator, (18 · 6, ) + (19 · 5, ) + (20 · 4, ) + (21 · 2, ) + (22 · 1, ) + (23 · 1, ) + (30 · 1, ), and denominator 20 = 20</strong>.Since the mode is 18, the median is 19, and the mean is 20, <strong>mode < median, which < mean</strong>.<br>Choices B and D are incorrect because the mean is greater than the median. Choice C is incorrect because the median is greater than the mode.<br>Alternate approach: After determining the mode, 18, and the median, 19, it remains to determine whether the mean is less than 19 or more than 19. Because the mean is a balancing point, there is as much deviation below the mean as above the mean. It is possible to compare the data to 19 to determine the balance of deviation above and below the mean. There is a total deviation of only 6 below 19 (the 6 values of 18); however, the data value 30 alone deviates by 11 above 19. Thus the mean must be greater than 19.",
hasFigure: false,
},
{
id: "560fab82",
type: "spr",
questionHtml:
"The table shows the frequency of values in a data set.<br><br>Value<br>Frequency<br><br><strong>19</strong><br><strong>7</strong><br><br><strong>21</strong><br><strong>1</strong><br><br><strong>23</strong><br><strong>7</strong><br><br><strong>25</strong><br><strong>4</strong><br><br>What is the minimum value of the data set?",
choices: [],
correctAnswer: "19",
explanation:
"The correct answer is <strong>19</strong>. The minimum value of a data set is the least value in the data set. The frequency refers to the number of times a value occurs. The given table shows that for this data set, the value <strong>19</strong> occurs <strong>7</strong> times, the value <strong>21</strong> occurs <strong>1</strong> time, the value <strong>23</strong> occurs <strong>7</strong> times, and the value <strong>25</strong> occurs <strong>4</strong> times. Therefore, of the values <strong>19</strong>, <strong>21</strong>, <strong>23</strong>, and <strong>25</strong> given in the data set, the minimum value of the data set is <strong>19</strong>.",
hasFigure: false,
},
{
id: "5c3c2e3c",
type: "mcq",
questionHtml:
"The weights, in pounds, for 15 horses in a stable were reported, and the mean, median, range, and standard deviation for the data were found. The horse with the lowest reported weight was found to actually weigh 10 pounds less than its reported weight. What value remains unchanged if the four values are reported using the corrected weight?",
choices: [
{ label: "A", text: "Mean" },
{ label: "B", text: "Median" },
{ label: "C", text: "Range" },
{ label: "D", text: "Standard deviation" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The median weight is found by ordering the horses weights from least to greatest and then determining the middle value from this list of weights. Decreasing the value for the horse with the lowest weight doesnt affect the median since its still the lowest value.Choice A is incorrect. The mean is calculated by finding the sum of all the weights of the horses and then dividing by the number of horses. Decreasing one of the weights would decrease the sum and therefore decrease the mean. Choice C is incorrect. Range is the difference between the highest and lowest weights, so decreasing the lowest weight would increase the range. Choice D is incorrect. Standard deviation is calculated based on the mean weight of the horses. Decreasing one of the weights decreases the mean and therefore would affect the standard deviation.",
hasFigure: false,
},
{
id: "7b65bb28",
type: "mcq",
questionHtml:
"In the table above, Melissa recorded the price of one gallon of regular gas from five different local gas stations on the same day. What is the median of the gas prices Melissa recorded?",
choices: [
{ label: "A", text: "$3.679" },
{ label: "B", text: "$3.689" },
{ label: "C", text: "$3.699" },
{ label: "D", text: "$3.729" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The median of a data set is the middle value when the data is in ascending or descending order. In ascending order, the gas prices are $3.609, $3.679, $3.699, $3.729, and $3.729. The middle number of this list is 3.699, so it follows that $3.699 is the median gas price.Choice A is incorrect. When the gas prices are listed in ascending order, this value isnt the middle number. Choice B is incorrect. This value represents the mean gas price. Choice D is incorrect. This value represents both the mode and the maximum gas price.",
hasFigure: false,
},
{
id: "8193e8cd",
type: "spr",
questionHtml:
"The mean of the list of numbers above is what fraction of the sum of the five numbers?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is <strong>one fifth</strong>. The mean of the list of numbers is found by dividing the sum of the numbers by the number of values in the list. Since there are 5 numbers in the list, the mean is <strong>one fifth</strong> of the sum of the numbers. Note that 1/5 and .2 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "881ef5f5",
type: "spr",
questionHtml:
"If a is the mean and b is the median of nine consecutive integers, what is the value of <strong>|, a b, |</strong> ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 0. Any nine consecutive integers can be written as <strong>k</strong>, <strong>k + 1</strong>, <strong>k + 2</strong>, <strong>k + 3</strong>, <strong>k + 4</strong>, <strong>k + 5</strong>, <strong>k + 6</strong>, <strong>k + 7</strong>, <strong>k + 8</strong>. The mean of the integers is their sum divided by 9: <strong>the fraction with numerator (k + k + 1 + k + 2 + dot dot dot + k + 8, ), and denominator 9 = the fraction with numerator, (9 k + 36, ), and denominator 9</strong>, which simplifies to <strong>k + 4</strong>. So <strong>a = k + 4</strong>. Since there is an odd number of integers (nine), the median is the integer in the middle when all the integers are ordered from least to greatest: <strong>k + 4</strong>. So <strong>b = k + 4</strong>. Therefore, <strong>| a b, | = |, (k + 4, ) (k + 4, ), |</strong>, which is 0.",
hasFigure: false,
},
{
id: "9110c120",
type: "mcq",
questionHtml:
"Which of the following statements about the means and medians of data set A and data set B is true?",
choices: [
{ label: "A", text: "Only the means are different." },
{ label: "B", text: "Only the medians are different." },
{ label: "C", text: "Both the means and the medians are different." },
{ label: "D", text: "Neither the means nor the medians are different." },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The mean of a data set is the sum of the values divided by the number of values. The mean of data set A is <strong>the fraction 45 over 9</strong>, or 5. The mean of data set B is <strong>the fraction 145 over 10</strong>, or 14.5. Thus, the means are different. The median of a data set is the middle value when the values are ordered from least to greatest. The medians of data sets A and B are both 5. Therefore, the medians are the same, so only the means are different.Choices B, C, and D are incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "9e2bf782",
type: "mcq",
questionHtml:
"A fish hatchery has three tanks for holding fish before they are introduced into the wild. Ten fish weighing less than 5 ounces are placed in tank A. Eleven fish weighing at least 5 ounces but no more than 13 ounces are placed in tank B. Twelve fish weighing more than 13 ounces are placed in tank C. Which of the following could be the median of the weights, in ounces, of these 33 fish?",
choices: [
{ label: "A", text: "4.5" },
{ label: "B", text: "8" },
{ label: "C", text: "13.5" },
{ label: "D", text: "15" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The median of a set of numbers is the middle number when the values in the set are ordered from least to greatest. There are 33 fish, so in an ordered list of the weights, the 17th value would be the median weight. The 10 fish in tank A weigh the least, and these 10 weights would be the first 10 values on the ordered list. The 11 fish in tank B have the next set of higher weights, and so would be the 11th through 21st weights in the ordered list, which includes the median weight as the 17th value. The fish in tank B weigh at least 5 ounces but no more than 13 ounces; of the given choices, only 8 ounces falls within this range of values.Choice A is incorrect. Its given that tank A has ten fish weighing less than 5 ounces. Since there are more than ten fish in tanks B and C combined, the median weight cannot be less than 5 ounces. Choice C and D are incorrect. Its given that tank C has twelve fish weighing more than 13 ounces. There are more than twelve fish in tanks A and B combined, so the median weight cant be more than 13 ounces.",
hasFigure: false,
},
{
id: "a456cfd2",
type: "spr",
questionHtml:
"Data value<br>Frequency<br><br><strong>6</strong><br><strong>3</strong><br><br><strong>7</strong><br><strong>3</strong><br><br><strong>8</strong><br><strong>8</strong><br><br><strong>9</strong><br><strong>8</strong><br><br><strong>10</strong><br><strong>9</strong><br><br><strong>11</strong><br><strong>11</strong><br><br><strong>12</strong><br><strong>9</strong><br><br><strong>13</strong><br><strong>0</strong><br><br><strong>14</strong><br><strong>6</strong><br><br>The frequency table summarizes the <strong>57</strong> data values in a data set. What is the maximum data value in the data set?",
choices: [],
correctAnswer: "14",
explanation:
"The correct answer is <strong>14</strong>. The maximum value is the largest value in the data set. The frequency refers to the number of times a data value occurs. The given frequency table shows that for this data set, the data value <strong>6</strong> occurs three times, the data value <strong>7</strong> occurs three times, the data value <strong>8</strong> occurs eight times, the data value <strong>9</strong> occurs eight times, the data value <strong>10</strong> occurs nine times, the data value <strong>11</strong> occurs eleven times, the data value <strong>12</strong> occurs nine times, the data value <strong>13</strong> occurs zero times, and the data value <strong>14</strong> occurs six times. Therefore, the maximum data value in the data set is <strong>14</strong>.",
hasFigure: false,
},
{
id: "be00d896",
type: "mcq",
questionHtml:
"For which of the following data sets is the mean greater than the median?",
choices: [
{ label: "A", text: "5, 5, 5, 5, 5, 5, 5, 5, 5" },
{ label: "B", text: "0, 10, 20, 30, 40, 50, 60, 70, 80" },
{ label: "C", text: "2, 4, 8, 16, 32, 64, 128, 256, 512" },
{ label: "D", text: "7, 107, 107, 207, 207, 207, 307, 307, 307" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. If the values in a data set are ordered from least to greatest, the median of the data set will be the middle value. Since each data set in the choices is ordered and contains exactly 9 data values, the 5th value in each is the median. It follows that the median of the data set in choice C is 32. The sum of the positive differences between 32 and each of the values that are less than 32 is significantly smaller than the sum of the positive differences between 32 and each of the values that are greater than 32. If 32 were the mean, these sums would have been equal to each other. Therefore, the mean of this data set must be greater than 32. This can also be confirmed by calculating the mean as the sum of the values divided by the number of values in the data set:  <strong>The fraction with numerator 2 + 4 + 8 + 16 + 32 + 64 + 128 + 256 + 512, and denominator 9 = 113 and five ninths</strong>.Choices A and B are incorrect. Each of the data sets in these choices is symmetric with respect to its median, so the mean and the median for each of these choices are equivalent. Choice D is incorrect. The median of this data set is 207. Since the sum of the positive differences between 207 and each of the values less than 207 is greater than the sum of the positive differences between 207 and each value greater than 207 in this data set, the mean must be less than the median.",
hasFigure: false,
},
{
id: "d0efc1dd",
type: "mcq",
questionHtml:
"The mean and the median of the five numbers above are equal. Which of the following is NOT a possible value of x ?",
choices: [
{ label: "A", text: "6" },
{ label: "B", text: "11" },
{ label: "C", text: "16" },
{ label: "D", text: "21" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. If x is 6, then the five numbers in the given list are 15, 14, 18, 17, 6. The mean of these five numbers is the sum of all the values divided by the number of values, or <strong>the fraction with numerator 15 + 14 + 18 + 17 + 6, and denominator 5, end fraction = 70 over 5, which = 14</strong>. The median of these five numbers can be found by ordering the numbers from least to greatest and determining the middle value. When ordered from least to greatest, the numbers in the given list are 6, 14, 15, 17, 18, and the middle value is 15. Since the mean is 14 and the median is 15, the mean and median arent equal when x is 6.Choices B, C, and D are incorrect. If any of these values is substituted for x, the mean and median of the data set would be equal.",
hasFigure: false,
},
{
id: "d94018fd",
type: "mcq",
questionHtml:
"For the dot plot titled Class A:<br><br>The number line ranges from 1 to 7 in increments of 1.<br>The data for the dot plot are as follows:<br><br>1: 1 dot<br>2: 1 dot<br>3: 3 dots<br>4: 4 dots<br>5: 5 dots<br>6: 6 dots<br>7: 7 dots<br><br>For the dot plot titled Class B:<br><br>The number line ranges from 14 to 20 in increments of 1.<br>The data for the dot plot are as follows:<br><br>14: 1 dot<br>15: 1 dot<br>16: 3 dots<br>17: 4 dots<br>18: 5 dots<br>19: 6 dots<br>20: 7 dots<br><br>Each of the dot plots shown represents the number of glue sticks brought in by each student for two classes, class A and class B. Which statement best compares the standard deviations of the numbers of glue sticks brought in by each student for these two classes?",
choices: [
{
label: "A",
text: "The standard deviation of the number of glue sticks brought in by each student for class A is less than the standard deviation of the number of glue sticks brought in by each student for class B.",
},
{
label: "B",
text: "The standard deviation of the number of glue sticks brought in by each student for class A is equal to the standard deviation of the number of glue sticks brought in by each student for class B.",
},
{
label: "C",
text: "The standard deviation of the number of glue sticks brought in by each student for class A is greater than the standard deviation of the number of glue sticks brought in by each student for class B.",
},
{
label: "D",
text: "There is not enough information to compare these standard deviations.",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. Standard deviation is a measure of the spread of a data set from its mean. The dot plot for class A and the dot plot for class B have the same shape. Thus, the frequency distributions for both class A and class B are the same. Since both class A and class B have the same frequency distribution of glue sticks brought in by each student, it follows that both class A and class B have the same spread of the number of glue sticks brought in by each student from their respective means. Therefore, the standard deviation of the number of glue sticks brought in by each student for class A is equal to the standard deviation of the number of glue sticks brought in by each student for class B.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/d94018fd_svg1.svg",
},
];
export const ONE_VAR_DATA_HARD: PracticeQuestion[] = [
{
id: "1142af44",
type: "mcq",
questionHtml:
"The frequency distribution above summarizes a set of data, where a is a positive integer. How much greater is the mean of the set of data than the median?",
choices: [
{ label: "A", text: "0" },
{ label: "B", text: "1" },
{ label: "C", text: "2" },
{ label: "D", text: "3" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Since the frequencies of values less than the middle value, 3, are the same as the frequencies of the values greater than 3, the set of data has a symmetric distribution. When a set of data has a symmetric distribution, the mean and median values are equal. Therefore, the mean is 0 greater than the median.Choices B, C, and D are incorrect and may result from misinterpreting the set of data.",
hasFigure: false,
},
{
id: "190be2fc",
type: "spr",
questionHtml:
"Data set A consists of <strong>10</strong> positive integers less than <strong>60</strong>. The list shown gives <strong>9</strong> of the integers from data set A.<br><strong>43</strong>, <strong>45</strong>, <strong>44</strong>, <strong>43</strong>, <strong>38</strong>, <strong>39</strong>, <strong>40</strong>, <strong>46</strong>, <strong>40</strong><br>The mean of these <strong>9</strong> integers is <strong>42</strong>. If the mean of data set A is an integer that is greater than <strong>42</strong>, what is the value of the largest integer from data set A?",
choices: [],
correctAnswer: "52",
explanation:
"The correct answer is <strong>52</strong>. The mean of a data set is calculated by dividing the sum of the data values by the number of values. Its given that data set A consists of <strong>10</strong> values, <strong>9</strong> of which are shown. Let <strong>x</strong> represent the <strong>10 th</strong> data value in data set A, which isnt shown. The mean of data set A can be found using the expression <strong>(43 + 45 + 44 + 43 + 38 + 39 + 40 + 46 + 40 + x) / (10)</strong>, or <strong>(378 + x) / (10)</strong>. Its given that the mean of the <strong>9</strong> values shown is <strong>42</strong> and that the mean of all <strong>10</strong> numbers is greater than <strong>42</strong>. Consequently, the <strong>10 th</strong> data value, <strong>x</strong>, is larger than <strong>42</strong>. Its also given that the data values in data set A are positive integers less than <strong>60</strong>. Thus, <strong>42 < x < 60</strong>. Finally, its given that the mean of data set A is an integer. This means that the sum of the <strong>10</strong> data values, <strong>378 + x</strong>, is divisible by <strong>10</strong>. Thus, <strong>378 + x</strong> must have a ones digit of <strong>0</strong>. It follows that <strong>x</strong> must have a ones digit of <strong>2</strong>. Since <strong>42 < x < 60</strong> and <strong>x</strong> has a ones digit of <strong>2</strong>, the only possible value of <strong>x</strong> is <strong>52</strong>. Since <strong>52</strong> is larger than any of the integers shown, the largest integer from data set A is <strong>52</strong>.",
hasFigure: false,
},
{
id: "1e8ccffd",
type: "mcq",
questionHtml:
"The mean score of 8 players in a basketball game was 14.5 points. If the highest individual score is removed, the mean score of the remaining 7 players becomes 12 points. What was the highest score?",
choices: [
{ label: "A", text: "20" },
{ label: "B", text: "24" },
{ label: "C", text: "32" },
{ label: "D", text: "36" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. If the mean score of 8 players is 14.5, then the total of all 8 scores is <strong>14 . 5 · 8 = 116</strong>. If the mean of 7 scores is 12, then the total of all 7 scores is <strong>12 · 7 = 84</strong>. Since the set of 7 scores was made by removing the highest score of the set of 8 scores, then the difference between the total of all 8 scores and the total of all 7 scores is equal to the removed score: <strong>116 84 = 32</strong>.Choice A is incorrect because if 20 is removed from the group of 8 scores, then the mean score of the remaining 7 players is <strong>the fraction with numerator, (14 . 5 · 8, ) 20, and denominator 7</strong> is approximately 13.71, not 12. Choice B is incorrect because if 24 is removed from the group of 8 scores, then the mean score of the remaining 7 players is <strong>the fraction with numerator, (14 . 5 · 8, ) 24, and denominator 7</strong> is approximately 13.14, not 12. Choice D is incorrect because if 36 is removed from the group of 8 scores, then the mean score of the remaining 7 players is <strong>the fraction with numerator, (14 . 5 · 8, ) 36, and denominator 7</strong> or approximately 11.43, not 12.",
hasFigure: false,
},
{
id: "2a59eb45",
type: "spr",
questionHtml:
"Data set A consists of the heights of <strong>75</strong> buildings and has a mean of <strong>32</strong> meters. Data set B consists of the heights of <strong>50</strong> buildings and has a mean of <strong>62</strong> meters. Data set C consists of the heights of the <strong>125</strong> buildings from data sets A and B. What is the mean, in meters, of data set C?",
choices: [],
correctAnswer: "44",
explanation:
"The correct answer is <strong>44</strong>. The mean of a data set is computed by dividing the sum of the values in the data set by the number of values in the data set. It's given that data set A consists of the heights of <strong>75</strong> buildings and has a mean of <strong>32</strong> meters. This can be represented by the equation <strong>(x) / (75) = 32</strong>, where <strong>x</strong> represents the sum of the heights of the buildings, in meters, in data set A. Multiplying both sides of this equation by <strong>75</strong> yields <strong>x = 75 (32)</strong>, or <strong>x = 2, 400</strong> meters. Therefore, the sum of the heights of the buildings in data set A is <strong>2, 400</strong> meters. It's also given that data set B consists of the heights of <strong>50</strong> buildings and has a mean of <strong>62</strong> meters. This can be represented by the equation <strong>(y) / (50) = 62</strong>, where <strong>y</strong> represents the sum of the heights of the buildings, in meters, in data set B. Multiplying both sides of this equation by <strong>50</strong> yields <strong>y = 50 (62)</strong>, or <strong>y = 3, 100</strong> meters. Therefore, the sum of the heights of the buildings in data set B is <strong>3, 100</strong> meters. Since it's given that data set C consists of the heights of the <strong>125</strong> buildings from data sets A and B, it follows that the mean of data set C is the sum of the heights of the buildings, in meters, in data sets A and B divided by the number of buildings represented in data sets A and B, or <strong>(2, 400 + 3, 100) / (125)</strong>, which is equivalent to <strong>44</strong> meters. Therefore, the mean, in meters, of data set C is <strong>44</strong>.",
hasFigure: false,
},
{
id: "391ae4b2",
type: "mcq",
questionHtml:
"Data set F consists of <strong>55</strong> integers between <strong>170</strong> and <strong>290</strong>. Data set G consists of all the integers in data set F as well as the integer <strong>10</strong>. Which of the following must be less for data set F than for data set G?<br><br>The mean<br>The median",
choices: [
{ label: "A", text: "I only" },
{ label: "B", text: "II only" },
{ label: "C", text: "I and II" },
{ label: "D", text: "Neither I nor II" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. It's given that data set F consists of <strong>55</strong> integers between <strong>170</strong> and <strong>290</strong> and data set G consists of all the integers in data set F as well as the integer <strong>10</strong>. Since the integer <strong>10</strong> is less than all the integers in data set F, the mean of data set G must be less than the mean of data set F. Thus, the mean of data set F isn't less than the mean of data set G. When a data set is in ascending order, the median is between the two middle values when there is an even number of values and the median is the middle value when there is an odd number of values. It follows that the median of data set F is either greater than or equal to the median of data set G. Therefore, the median of data set F isn't less than the median of data set G. Thus, neither the mean nor the median must be less for data set F than for data set G.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "457d2f2c",
type: "mcq",
questionHtml:
"A data set of 27 different numbers has a mean of 33 and a median of 33. A new data set is created by adding 7 to each number in the original data set that is greater than the median and subtracting 7 from each number in the original data set that is less than the median. Which of the following measures does NOT have the same value in both the original and new data sets?",
choices: [
{ label: "A", text: "Median" },
{ label: "B", text: "Mean" },
{ label: "C", text: "Sum of the numbers" },
{ label: "D", text: "Standard deviation" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. When a data set has an odd number of elements, the median can be found by ordering the values from least to greatest and determining the middle value. Out of the 27 different numbers in this data set, 13 numbers are below the median, one number is exactly 33, and 13 numbers are above the median. When 7 is subtracted from each number below the median and added to each number above the median, the data spread out from the median. Since the median of this data set, 33, is equivalent to the mean of the data set, the data also spread out from the mean. Since standard deviation is a measure of how spread out the data are from the mean, a greater spread from the mean indicates an increased standard deviation.Choice A is incorrect. All the numbers less than the median decrease and all the numbers greater than the median increase, but the median itself doesnt change. Choices B and C are incorrect. The mean of a data set is found by dividing the sum of the values by the number of values. The net change from subtracting 7 from 13 numbers and adding 7 to 13 numbers is zero. Therefore, neither the mean nor the sum of the numbers changes.",
hasFigure: false,
},
{
id: "4626102e",
type: "mcq",
questionHtml:
"The data for the dot plot are as follows:<br><br>22: 5 dots<br>23: 4 dots<br>24: 3 dots<br>25: 2 dots<br>26: 1 dot<br><br>The dot plot represents the <strong>15</strong> values in data set A. Data set B is created by adding <strong>56</strong> to each of the values in data set A. Which of the following correctly compares the medians and the ranges of data sets A and B?",
choices: [
{
label: "A",
text: "The median of data set B is equal to the median of data set A, and the range of data set B is equal to the range of data set A.",
},
{
label: "B",
text: "The median of data set B is equal to the median of data set A, and the range of data set B is greater than the range of data set A.",
},
{
label: "C",
text: "The median of data set B is greater than the median of data set A, and the range of data set B is equal to the range of data set A.",
},
{
label: "D",
text: "The median of data set B is greater than the median of data set A, and the range of data set B is greater than the range of data set A.",
},
],
correctAnswer: "C",
explanation:
"Choice C is correct. The median of a data set with an odd number of values, in ascending or descending order, is the middle value of the data set, and the range of a data set is the positive difference between the maximum and minimum values in the data set. Since the dot plot shown gives the values in data set A in ascending order and there are <strong>15</strong> values in the data set, the eighth value in data set A, <strong>23</strong>, is the median. The maximum value in data set A is <strong>26</strong> and the minimum value is <strong>22</strong>, so the range of data set A is <strong>26 22</strong>, or <strong>4</strong>. Its given that data set B is created by adding <strong>56</strong> to each of the values in data set A. Increasing each of the <strong>15</strong> values in data set A by <strong>56</strong> will also increase its median value by <strong>56</strong> making the median of data set B <strong>79</strong>. Increasing each value of data set A by <strong>56</strong> does not change the range, since the maximum value of data set B is <strong>26 + 56</strong>, or <strong>82</strong>, and the minimum value is <strong>22 + 56</strong>, or <strong>78</strong>, making the range of data set B <strong>82 78</strong>, or <strong>4</strong>. Therefore, the median of data set B is greater than the median of data set A, and the range of data set B is equal to the range of data set A.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/4626102e_svg1.svg",
},
{
id: "4ff597db",
type: "mcq",
questionHtml:
"The mean amount of time that the 20 employees of a construction company have worked for the company is 6.7 years. After one of the employees leaves the company, the mean amount of time that the remaining employees have worked for the company is reduced to 6.25 years. How many years did the employee who left the company work for the company?",
choices: [
{ label: "A", text: "0.45" },
{ label: "B", text: "2.30" },
{ label: "C", text: "9.00" },
{ label: "D", text: "15.25" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The mean amount of time that the 20 employees worked for the company is 6.7 years. This means that the total number of years all 20 employees worked for the company is (6.7)(20) = 134 years. After the employee left, the mean amount of time that the remaining 19 employees worked for the company is 6.25 years. Therefore, the total number of years all 19 employees worked for the company is (6.25)(19) = 118.75 years. It follows that the number of years that the employee who left had worked for the company is 134 118.75 = 15.25 years.Choice A is incorrect; this is the change in the mean, which isnt the same as the amount of time worked by the employee who left. Choice B is incorrect and likely results from making the assumption that there were still 20 employees, rather than 19, at the company after the employee left and then subtracting the original mean of 6.7 from that result. Choice C is incorrect and likely results from making the assumption that there were still 20 employees, rather than 19, at the company after the employee left.",
hasFigure: false,
},
{
id: "54d93874",
type: "spr",
questionHtml:
"Andrew and Maria each collected six rocks, and the masses of the rocks are shown in the table above. The mean of the masses of the rocks Maria collected is 0.1 kilogram greater than the mean of the masses of the rocks Andrew collected. What is the value of x ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 2.6. Since the mean of a set of numbers can be found by adding the numbers together and dividing by how many numbers there are in the set, the mean mass, in kilograms, of the rocks Andrew collected is <strong>the fraction with numerator 2 . 4 + 2 . 5 + 3 . 6 + 3 . 1 + 2 . 5 + 2 . 7, and denominator 6 = 16 . 8 over 6.</strong>, or 2.8. Since the mean mass of the rocks Maria collected is 0.1 kilogram greater than the mean mass of rocks Andrew collected, the mean mass of the rocks Maria collected is <strong>2 . 8 + 0 . 1 = 2 . 9</strong> kilograms. The value of x can be found by writing an equation for finding the mean: <strong>the fraction with numerator x + 3 . 1 + 2 . 7 + 2 . 9 + 3 . 3 + 2 . 8, and denominator 6 = 2 . 9</strong>. Solving this equation gives <strong>x = 2 . 6</strong>. Note that 2.6 and 13/5 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "651d83bb",
type: "mcq",
questionHtml:
"Which of the following MUST be true?Every member of team A completed the race in less time than any member of team B.<br> The median time it took the members of team B to complete the race is greater than the median time it took the members of team A to complete the race.<br> There is at least one member of team B who took more time to complete the race than some member of team A.",
choices: [
{ label: "A", text: "III only" },
{ label: "B", text: "I and III only" },
{ label: "C", text: "II and III only" },
{ label: "D", text: "I, II, and III" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Since the average time for the 10 members of team A is 3.41 minutes, the sum of the 10 times for team A is equal to <strong>10 · 3 . 4 1 = 34 . 1</strong> minutes. Since the average time for the 10 members of team B is 3.79 minutes, the sum of the 10 times for team B is equal to <strong>10 · 3 . 7 9 = 37 . 9</strong> minutes. Since the sum of the 10 times for team B is greater than the sum of the 10 times for team A, it must be true that at least one of the times for team B must be greater than one of the times for team A. Thus, statement III is true. However, its possible that at least some of the times for team A were greater than some of the times for team B. For example, all of team As times could be 3.41 minutes, and team B could have 1 time of 3.34 minutes and 9 times of 3.84 minutes. Thus, statement I need not be true. Its also possible that the median of the times for team B is less than the median of the times for team A. For example, all of team As times could be 3.41 minutes, and team B could have 6 times of 3.37 minutes and 4 times of 4.42 minutes; then the median of team Bs times would be 3.37 minutes and the median of team As times would be 3.41 minutes. Thus, statement II need not be true.Choices B, C, and D are incorrect because neither statement I nor statement II must be true.",
hasFigure: false,
},
{
id: "94237701",
type: "spr",
questionHtml:
"The median of the scores for group B is how much greater than the median of the scores for group A?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 1. When there are an odd number of values in a data set, the median of the data set is the middle number when the data values are ordered from least to greatest. The scores for group A, ordered from least to greatest, are 2, 3, 4, 4, 5, 6, 6, 6, and 9. The median of the scores for group A is therefore 5. The scores for group B, ordered from least to greatest, are 5, 5, 5, 5, 6, 6, 8, 8, 9, 10, and 10. The median of the scores for group B is therefore 6. The median score for group B is <strong>6 5 = 1</strong> more than the median score for group A.",
hasFigure: false,
},
{
id: "98958ae8",
type: "spr",
questionHtml:
"Data set A consists of the heights of <strong>75</strong> objects and has a mean of <strong>25</strong> meters. Data set B consists of the heights of <strong>50</strong> objects and has a mean of <strong>65</strong> meters. Data set C consists of the heights of the <strong>125</strong> objects from data sets A and B. What is the mean, in meters, of data set C?",
choices: [],
correctAnswer: "41",
explanation:
"The correct answer is <strong>41</strong>. The mean of a data set is computed by dividing the sum of the values in the data set by the number of values in the data set. Its given that data set A consists of the heights of <strong>75</strong> objects and has a mean of <strong>25</strong> meters. This can be represented by the equation <strong>(x) / (75) = 25</strong>, where <strong>x</strong> represents the sum of the heights of the objects, in meters, in data set A. Multiplying both sides of this equation by <strong>75</strong> yields <strong>x = 75 (25)</strong>, or <strong>x = 1, 875</strong> meters. Therefore, the sum of the heights of the objects in data set A is <strong>1, 875</strong> meters. Its also given that data set B consists of the heights of <strong>50</strong> objects and has a mean of <strong>65</strong> meters. This can be represented by the equation <strong>(y) / (50) = 65</strong>, where <strong>y</strong> represents the sum of the heights of the objects, in meters, in data set B. Multiplying both sides of this equation by <strong>50</strong> yields <strong>y = 50 (65)</strong>, or <strong>y = 3, 250</strong> meters. Therefore, the sum of the heights of the objects in data set B is <strong>3, 250</strong> meters. Since its given that data set C consists of the heights of the <strong>125</strong> objects from data sets A and B, it follows that the mean of data set C is the sum of the heights of the objects, in meters, in data sets A and B divided by the number of objects represented in data sets A and B, or <strong>(1, 875 + 3, 250) / (125)</strong>, which is equivalent to <strong>41</strong> meters. Therefore, the mean, in meters, of data set C is <strong>41</strong>.",
hasFigure: false,
},
{
id: "9d935bd8",
type: "mcq",
questionHtml:
"A survey was given to residents of all 50 states asking if they had earned a bachelors degree or higher. The results from 7 of the states are given in the table above. The median percent of residents who earned a bachelors degree or higher for all 50 states was 26.95%. What is the difference between the median percent of residents who earned a bachelors degree or higher for these 7 states and the median for all 50 states?",
choices: [
{ label: "A", text: "0.05%" },
{ label: "B", text: "0.95%" },
{ label: "C", text: "1.22%" },
{ label: "D", text: "7.45%" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The median of a set of numbers is the middle value of the set values when ordered from least to greatest. If the percents in the table are ordered from least to greatest, the middle value is 27.9%. The difference between 27.9% and 26.95% is 0.95%.Choice A is incorrect and may be the result of calculation errors or not finding the median of the data in the table correctly. Choice C is incorrect and may be the result of finding the mean instead of the median. Choice D is incorrect and may be the result of using the middle value of the unordered list.",
hasFigure: true,
figureUrl: "/practice-images/9d935bd8_img1.png",
},
{
id: "bf47ad54",
type: "mcq",
questionHtml:
"Each of the following frequency tables represents a data set. Which data set has the greatest mean?",
choices: [
{
label: "A",
text: "Value<br>Frequency<br><br><strong>70</strong><br><strong>4</strong><br><br><strong>80</strong><br><strong>5</strong><br><br><strong>90</strong><br><strong>6</strong><br><br><strong>100</strong><br><strong>7</strong>",
},
{
label: "B",
text: "Value<br>Frequency<br><br><strong>70</strong><br><strong>6</strong><br><br><strong>80</strong><br><strong>6</strong><br><br><strong>90</strong><br><strong>6</strong><br><br><strong>100</strong><br><strong>6</strong>",
},
{
label: "C",
text: "Value<br>Frequency<br><br><strong>70</strong><br><strong>7</strong><br><br><strong>80</strong><br><strong>6</strong><br><br><strong>90</strong><br><strong>6</strong><br><br><strong>100</strong><br><strong>7</strong>",
},
{
label: "D",
text: "Value<br>Frequency<br><br><strong>70</strong><br><strong>8</strong><br><br><strong>80</strong><br><strong>5</strong><br><br><strong>90</strong><br><strong>5</strong><br><br><strong>100</strong><br><strong>8</strong>",
},
],
correctAnswer: "A",
explanation:
"Choice A is correct. The tables in choices B, C, and D each represent a data set where the values <strong>80</strong> and <strong>90</strong> have the same frequency and the values <strong>70</strong> and <strong>100</strong> have the same frequency. It follows that each of these data sets is symmetric around the value halfway between <strong>80</strong> and <strong>90</strong>, or <strong>85</strong>. When a data set is symmetric around a value, that value is the mean of the data set. Therefore, the data sets represented by the tables in choices B, C, and D each have a mean of <strong>85</strong>. The table in choice A represents a data set where the value <strong>90</strong> has a greater frequency than the value <strong>80</strong> and the value <strong>100</strong> has a greater frequency than the value <strong>70</strong>. It follows that this data set has a mean greater than <strong>85</strong>. Therefore, of the given choices, choice A represents the data set with the greatest mean.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "c178d4da",
type: "mcq",
questionHtml:
"Value<br>Data set A frequency<br>Data set B frequency<br><br><strong>30</strong><br><strong>2</strong><br><strong>9</strong><br><br><strong>34</strong><br><strong>4</strong><br><strong>7</strong><br><br><strong>38</strong><br><strong>5</strong><br><strong>5</strong><br><br><strong>42</strong><br><strong>7</strong><br><strong>4</strong><br><br><strong>46</strong><br><strong>9</strong><br><strong>2</strong><br><br>Data set A and data set B each consist of <strong>27</strong> values. The table shows the frequencies of the values for each data set. Which of the following statements best compares the means of the two data sets?",
choices: [
{
label: "A",
text: "The mean of data set A is greater than the mean of data set B.",
},
{
label: "B",
text: "The mean of data set A is less than the mean of data set B.",
},
{
label: "C",
text: "The mean of data set A is equal to the mean of data set B.",
},
{
label: "D",
text: "There is not enough information to compare the means of the data sets.",
},
],
correctAnswer: "A",
explanation:
"Choice A is correct. The mean value of a data set is the sum of the values of the data set divided by the number of values in the data set. When a data set is represented in a frequency table, the sum of the values in the data set is the sum of the products of each value and its frequency. For data set A, the sum of products of each value and its frequency is <strong>30 (2) + 34 (4) + 38 (5) + 42 (7) + 46 (9)</strong>, or <strong>1, 094</strong>. It's given that there are <strong>27</strong> values in data set A. Therefore, the mean of data set A is <strong>(1, 094) / (27)</strong>, or approximately <strong>40.52</strong>. Similarly, the mean of data B is <strong>(958) / (27)</strong>, or approximately <strong>35.48</strong>. Therefore, the mean of data set A is greater than the mean of data set B.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "d3b9c8d8",
type: "mcq",
questionHtml:
"From left to right the values of the vertical bars in the Group 1 box plot are as follows:<br><br>First vertical bar: 21<br>Second vertical bar: 22<br>Third vertical bar: 25<br>Fourth vertical bar: 26<br>Fifth vertical bar: 28<br><br>From left to right the values of the vertical bars in the Group 2 box plot are as follows:<br><br>First vertical bar: 22<br>Second vertical bar: 23<br>Third vertical bar: 24<br>Fourth vertical bar: 25<br>Fifth vertical bar: 28<br><br>The box plots summarize the masses, in kilograms, of two groups of gazelles. Based on the box plots, which of the following statements must be true?",
choices: [
{
label: "A",
text: "The mean mass of group 1 is greater than the mean mass of group 2.",
},
{
label: "B",
text: "The mean mass of group 1 is less than the mean mass of group 2.",
},
{
label: "C",
text: "The median mass of group 1 is greater than the median mass of group 2.",
},
{
label: "D",
text: "The median mass of group 1 is less than the median mass of group 2.",
},
],
correctAnswer: "C",
explanation:
"Choice C is correct. The median of a data set represented in a box plot is represented by the vertical line within the box. It follows that the median mass of the gazelles in group <strong>1</strong> is <strong>25</strong> kilograms, and the median mass of the gazelles in group <strong>2</strong> is <strong>24</strong> kilograms. Since <strong>25</strong> kilograms is greater than <strong>24</strong> kilograms, the median mass of group <strong>1</strong> is greater than the median mass of group <strong>2</strong>.<br>Choice A is incorrect. The mean mass of each of the two groups cannot be determined from the box plots.<br>Choice B is incorrect. The mean mass of each of the two groups cannot be determined from the box plots.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/d3b9c8d8_svg1.svg",
},
{
id: "d65b9a87",
type: "mcq",
questionHtml:
"The dot plots represent the distributions of values in data sets A and B.<br>For the dot plot titled Data Set A:<br><br>The number line ranges from 10 to 16 in increments of 1.<br>The data for the dot plot are as follows:<br><br>10: 1 dot<br>11: 4 dots<br>12: 2 dots<br>13: 3 dots<br>14: 2 dots<br>15: 4 dots<br>16: 1 dot<br><br>For the dot plot titled Data Set B:<br><br>The number line ranges from 10 to 16 in increments of 1.<br>The data for the dot plot are as follows:<br><br>10: 2 dots<br>11: 4 dots<br>12: 2 dots<br>13: 1 dot<br>14: 2 dots<br>15: 4 dots<br>16: 2 dots<br><br>Which of the following statements must be true?<br><br>The median of data set A is equal to the median of data set B.<br>The standard deviation of data set A is equal to the standard deviation of data set B.",
choices: [
{ label: "A", text: "I only" },
{ label: "B", text: "II only" },
{ label: "C", text: "I and II" },
{ label: "D", text: "Neither I nor II" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The median of a data set with an odd number of values that are in ascending or descending order is the middle value of the data set. Since the distribution of the values of both data set A and data set B form symmetric dot plots, and each data set has an odd number of values, it follows that the median is given by the middle value in each of the dot plots. Thus, the median of data set A is <strong>13</strong>, and the median of data set B is <strong>13</strong>. Therefore, statement I is true. Data set A and data set B have the same frequency for each of the values <strong>11</strong>, <strong>12</strong>, <strong>14</strong>, and <strong>15</strong>. Data set A has a frequency of <strong>1</strong> for values <strong>10</strong> and <strong>16</strong>, whereas data set B has a frequency of <strong>2</strong> for values <strong>10</strong> and <strong>16</strong>. Standard deviation is a measure of the spread of a data set; it is larger when there are more values further from the mean, and smaller when there are more values closer to the mean. Since both distributions are symmetric with an odd number of values, the mean of each data set is equal to its median. Thus, each data set has a mean of <strong>13</strong>. Since more of the values in data set A are closer to <strong>13</strong> than data set B, it follows that data set A has a smaller standard deviation than data set B. Thus, statement II is false. Therefore, only statement I must be true.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/d65b9a87_svg1.svg",
},
{
id: "f8a322d9",
type: "mcq",
questionHtml:
"Data Set A:<br><br>The horizontal axis is labeled Integer. It ranges from 10 to 60 and is divided into 5 equal intervals.<br>The vertical axis is labeled Frequency. It ranges from 0 to 12 in increments of 1, with values marked every 2 grid lines.<br>The histogram has a skewed right shape.<br>The histogram has 4 bins.<br>The Frequency data for the 4 bins are as follows:<br><br>20 to 30: 3<br>30 to 40: 4<br>40 to 50: 7<br>50 to 60: 9<br><br>Data Set B:<br><br>The horizontal axis is labeled Integer. It ranges from 10 to 60 and is divided into 5 equal intervals.<br>The vertical axis is labeled Frequency. It ranges from 0 to 12 in increments of 1, with values marked every 2 grid lines.<br>The histogram has a skewed right shape.<br>The histogram has 4 bins.<br>The Frequency data for the 4 bins are as follows:<br><br>10 to 20: 3<br>20 to 30: 4<br>30 to 40: 7<br>40 to 50: 9<br><br>Two data sets of <strong>23</strong> integers each are summarized in the histograms shown. For each of the histograms, the first interval represents the frequency of integers greater than or equal to <strong>10</strong>, but less than <strong>20</strong>. The second interval represents the frequency of integers greater than or equal to <strong>20</strong>, but less than <strong>30</strong>, and so on. What is the smallest possible difference between the mean of data set A and the mean of data set B?",
choices: [
{ label: "A", text: "<strong>0</strong>" },
{ label: "B", text: "<strong>1</strong>" },
{ label: "C", text: "<strong>10</strong>" },
{ label: "D", text: "<strong>23</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The histograms shown have the same shape, but data set A contains values between <strong>20</strong> and <strong>60</strong> and data set B contains values between <strong>10</strong> and <strong>50</strong>. Thus, the mean of data set A is greater than the mean of data set B. Therefore, the smallest possible difference between the mean of data set A and the mean of data set B is the difference between the smallest possible mean of data set A and the greatest possible mean of data set B. In data set A, since there are <strong>3</strong> integers in the interval greater than or equal to <strong>20</strong> but less than <strong>30</strong>, <strong>4</strong> integers greater than or equal to <strong>30</strong> but less than <strong>40</strong>, <strong>7</strong> integers greater than or equal to <strong>40</strong> but less than <strong>50</strong>, and <strong>9</strong> integers greater than or equal to <strong>50</strong> but less than <strong>60</strong>, the smallest possible mean for data set A is <strong>((3 dot 20) + (4 dot 30) + (7 dot 40) + (9 dot 50)) / (23)</strong>. In data set B, since there are <strong>3</strong> integers greater than or equal to <strong>10</strong> but less than <strong>20</strong>, <strong>4</strong> integers greater than or equal to <strong>20</strong> but less than <strong>30</strong>, <strong>7</strong> integers greater than or equal to <strong>30</strong> but less than <strong>40</strong>, and <strong>9</strong> integers greater than or equal to <strong>40</strong> but less than <strong>50</strong>, the largest possible mean for data set B is <strong>((3 dot 19) + (4 dot 29) + (7 dot 39) + (9 dot 49)) / (23)</strong>. Therefore, the smallest possible difference between the mean of data set A and the mean of data set B is <strong>((3 dot 20) + (4 dot 30) + (7 dot 40) + (9 dot 50)) / (23) ((3 dot 19) + (4 dot 29) + (7 dot 39) + (9 dot 49)) / (23)</strong>, which is equivalent to <strong>((3 dot 20) (3 dot 19) + (4 dot 30) (4 dot 29) + (7 dot 40) (7 dot 39) + (9 dot 50) (9 dot 49)) / (23)</strong>. This expression can be rewritten as <strong>(3 (20 19) + 4 (30 29) + 7 (40 39) + 9 (50 49)) / (23)</strong>, or <strong>(23) / (23)</strong>, which is equal to <strong>1</strong>. Therefore, the smallest possible difference between the mean of data set A and the mean of data set B is <strong>1</strong>.<br>Choice A is incorrect. This is the smallest possible difference between the ranges, not the means, of the data sets.<br>Choice C is incorrect. This is the difference between the greatest possible mean, not the smallest possible mean, of data set A and the greatest possible mean of data set B.<br>Choice D is incorrect. This is the smallest possible difference between the sum of the values in data set A and the sum of the values in data set B, not the smallest possible difference between the means.",
hasFigure: true,
figureUrl: "/practice-images/f8a322d9_svg1.svg",
},
];

View File

@ -0,0 +1,783 @@
import { type PracticeQuestion } from "../../types/lesson";
export const PERCENTAGES_EASY: PracticeQuestion[] = [
{
id: "048811bd",
type: "mcq",
questionHtml: "What is <strong>10 % sign</strong> of <strong>370</strong>?",
choices: [
{ label: "A", text: "<strong>27</strong>" },
{ label: "B", text: "<strong>37</strong>" },
{ label: "C", text: "<strong>333</strong>" },
{ label: "D", text: "<strong>360</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. <strong>10 % sign</strong> of a quantity means <strong>(10) / (100)</strong> times the quantity. Therefore, <strong>10 % sign</strong> of <strong>370</strong> can be represented as <strong>(10) / (100) (370)</strong>, which is equivalent to <strong>0.10 (370)</strong>, or <strong>37</strong>. Therefore, <strong>10 % sign</strong> of <strong>370</strong> is <strong>37</strong>.<br>Choice A is incorrect. This is <strong>10 % sign</strong> of <strong>270</strong>, not <strong>10 % sign</strong> of <strong>370</strong>.<br>Choice C is incorrect. This is <strong>90 % sign</strong> of <strong>370</strong>, not <strong>10 % sign</strong> of <strong>370</strong>.<br>Choice D is incorrect. This is <strong>370 10</strong>, not <strong>10 % sign</strong> of <strong>370</strong>.",
hasFigure: false,
},
{
id: "191d167b",
type: "mcq",
questionHtml:
"Last year, <strong>200</strong> students enrolled in an interior design program. This year, the number of students enrolled is <strong>147 % sign</strong> of last years number. How many students are enrolled in the interior design program this year?",
choices: [
{ label: "A", text: "<strong>247</strong>" },
{ label: "B", text: "<strong>294</strong>" },
{ label: "C", text: "<strong>347</strong>" },
{ label: "D", text: "<strong>394</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. It's given that the number of students enrolled in an interior design program this year is <strong>147 % sign</strong> of last year's number, which is <strong>200</strong>. <strong>147 % sign</strong> of <strong>200</strong> can be expressed as <strong>((147) / (100)) (200)</strong>, or <strong>(1.47) (200)</strong>, which is equivalent to <strong>294</strong>. Therefore, <strong>294</strong> students are enrolled in the interior design program this year.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "194ae3b1",
type: "mcq",
questionHtml:
"There were approximately 113,000 occupational therapy jobs in the United States in 2012. The Bureau of Labor Statistics has projected that this number will increase by 29% from 2012 to 2022. Of the following, which is closest to the number of occupational therapy jobs the bureau has projected for the United States in 2022?",
choices: [
{ label: "A", text: "115,900" },
{ label: "B", text: "116,300" },
{ label: "C", text: "142,000" },
{ label: "D", text: "145,800" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The decimal equivalent of 29% is 0.29. Its given that the 113,000 occupational therapy jobs in the United States in 2012 are projected to increase by 29% by 2022. Increasing 113,000 by 29% can be expressed as <strong>113, 000 · (1 + 0 . 2 9, )</strong>, or <strong>113, 000 · 1 . 2 9</strong>. Evaluating this expression yields 145,770. The closest number is 145,800 in choice D.Choice A is incorrect and may result from increasing 113,000 by 2,900 instead of by 29%. Choice B is incorrect and may result from increasing 113,000 by 2.9% instead of by 29%. Choice C is incorrect and may result from increasing 113,000 by 29,000 instead of by 29%.",
hasFigure: false,
},
{
id: "1c2f50a6",
type: "mcq",
questionHtml:
"During a sale, the original prices of all the items in a clothing store have been reduced by 20%. What is the sale price of a jacket with an original price of $50 ?",
choices: [
{ label: "A", text: "$12" },
{ label: "B", text: "$30" },
{ label: "C", text: "$36" },
{ label: "D", text: "$40" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Its given that the original price of the jacket has been reduced by 20%. Multiplying the original price, $50, by 20% gives the amount, in dollars, that the price of the jacket is reduced by: <strong>50 · . 2 0 = 10</strong>. Subtracting this value from the original price results in the sale price of the jacket: <strong>50 dollars 10 dollars</strong>, or $40.Choices A, B, and C are incorrect and may result from a conceptual or calculation error.",
hasFigure: false,
},
{
id: "273b7f37",
type: "mcq",
questionHtml:
"Isabel grows potatoes in her garden. This year, she harvested <strong>760</strong> potatoes and saved <strong>10 % sign</strong> of them to plant next year. How many of the harvested potatoes did Isabel save to plant next year?",
choices: [
{ label: "A", text: "<strong>66</strong>" },
{ label: "B", text: "<strong>76</strong>" },
{ label: "C", text: "<strong>84</strong>" },
{ label: "D", text: "<strong>86</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The number of harvested potatoes Isabel saved to plant next year can be calculated by multiplying the total number of potatoes Isabel harvested, <strong>760</strong>, by the proportion of potatoes she saved. Since she saved <strong>10 % sign</strong> of the potatoes she harvested, the proportion of potatoes she saved is <strong>(10) / (100)</strong>, or <strong>0.1</strong>. Multiplying <strong>760</strong> by this proportion gives <strong>760 (0.1)</strong>, or <strong>76</strong>, potatoes that she saved to plant next year.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "28c6bd8c",
type: "mcq",
questionHtml:
"The table above shows a summary of 1,200 responses to a survey question. Based on the table, how many of those surveyed get most of their medical information from either a doctor or the Internet?",
choices: [
{ label: "A", text: "865" },
{ label: "B", text: "887" },
{ label: "C", text: "912" },
{ label: "D", text: "926" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. According to the table, 63% of survey respondents get most of their medical information from a doctor and 13% get most of their medical information from the Internet. Therefore, 76% of the 1,200 survey respondents get their information from either a doctor or the Internet, and 76% of 1,200 is 912.Choices A, B, and D are incorrect. According to the table, 76% of survey respondents get their information from either a doctor or the Internet. Choice A is incorrect because 865 is about 72% (the percent of survey respondents who get most of their medical information from a doctor or from magazines/brochures), not 76%, of 1,200. Choice B is incorrect because 887 is about 74%, not 76%, of 1,200. Choice D is incorrect because 926 is about 77%, not 76%, of 1,200.",
hasFigure: true,
figureUrl: "/practice-images/28c6bd8c_img1.png",
},
{
id: "29c177e6",
type: "mcq",
questionHtml: "What is <strong>10 % sign</strong> of <strong>470</strong>?",
choices: [
{ label: "A", text: "<strong>37</strong>" },
{ label: "B", text: "<strong>47</strong>" },
{ label: "C", text: "<strong>423</strong>" },
{ label: "D", text: "<strong>460</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. <strong>10 % sign</strong> of a quantity means <strong>(10) / (100)</strong> times the quantity. Therefore, <strong>10 % sign</strong> of <strong>470</strong> can be represented as <strong>(10) / (100) (470)</strong>, which is equivalent to <strong>0.10 (470)</strong>, or <strong>47</strong>. Therefore, <strong>10 % sign</strong> of <strong>470</strong> is <strong>47</strong>.<br>Choice A is incorrect. This is <strong>10 % sign</strong> of <strong>370</strong>, not <strong>10 % sign</strong> of <strong>470</strong>.<br>Choice C is incorrect. This is <strong>90 % sign</strong> of <strong>470</strong>, not <strong>10 % sign</strong> of <strong>470</strong>.<br>Choice D is incorrect. This is <strong>470 10</strong>, not <strong>10 % sign</strong> of <strong>470</strong>.",
hasFigure: false,
},
{
id: "2d31caae",
type: "mcq",
questionHtml:
"Call Ratings<br> <br> 1 Star<br> 2 Stars<br> 3 Stars<br> 4 Stars<br> Total<br> Employee A <br> 16<br> 49<br> 72<br> 8<br> 145<br> Employee B<br> <br> 4<br><br> <br> 10<br> 22<br> 34<br> 70<br> Employee C<br> 8<br> 56<br> 45<br> 16<br> 125<br> Employee D<br> 22<br> 42<br> 84<br> 12<br> 160<br> Total<br> 50<br> 157<br> 223<br> 70<br> 500<br> <br>A supervisor at a call center reviewed 500 calls taken by four employees and rated the employees performance on each call on a scale from 1 star to 4 stars. The ratings for each employee are shown in the table above. According to the table, to the nearest whole percent, what percent of Employee As calls received a rating of 1 star?",
choices: [
{ label: "A", text: "3%" },
{ label: "B", text: "11%" },
{ label: "C", text: "16%" },
{ label: "D", text: "32%" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The percent of Employee As calls that received a rating of 1 star is the number of Employee As 1-star calls divided by the total number of Employee As calls. This quotient, <strong>16 over 145</strong>, is approximately equal to <strong>0 . 1 1 0 3</strong>, or <strong>11 . 0 3 %</strong>. To the nearest whole percent, this is 11%.<br><br>Choice A is incorrect. This is the percent of all calls taken by Employee A that received a rating of 1 star. Choice C is incorrect and may result from a conceptual error. For example, 16 is the number, not the percent, of calls taken by Employee A that received a rating of 1 star. Choice D is incorrect. This is the percent of all calls that received a rating of 1 star that were taken by Employee A.",
hasFigure: false,
},
{
id: "3a6ed720",
type: "mcq",
questionHtml:
"Of <strong>900, 000</strong> beads, <strong>828, 000</strong> are silver. What percentage of the beads are silver?",
choices: [
{ label: "A", text: "<strong>8 % sign</strong>" },
{ label: "B", text: "<strong>36 % sign</strong>" },
{ label: "C", text: "<strong>72 % sign</strong>" },
{ label: "D", text: "<strong>92 % sign</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The proportion of the beads that are silver can be written as <strong>(828, 000) / (900, 000)</strong>, or <strong>0.92</strong>. Therefore, the percentage of the beads that are silver is <strong>0.92 (100)</strong>, or <strong>92 % sign</strong>.<br>Choice A is incorrect. This is the percentage of the beads that are not silver.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "41b71b4e",
type: "mcq",
questionHtml: "What number is 20% greater than 60 ?",
choices: [
{ label: "A", text: "50" },
{ label: "B", text: "72" },
{ label: "C", text: "75" },
{ label: "D", text: "132" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The decimal equivalent of 20% is 0.2. The number that is 20% greater than 60 is also 120% of 60. The decimal equivalent of 120% is 1.2, and <strong>1 . 2 · 60 = 72</strong>.Alternate approach: 10% of 60 is 6, and 20% of 60 is double that amount, or 12. It follows that the number that is 20% greater than 60 is 12 more than 60, or <strong>60 + 12 = 72</strong>.<br>Choice A is incorrect and may result from dividing, instead of multiplying, 60 by 1.2. Choice C is incorrect because its 25% greater than 60, rather than 20% greater than 60. Choice D is incorrect and may result from multiplying 60 by 2.2 instead of 1.2.",
hasFigure: false,
},
{
id: "6e4a60dd",
type: "mcq",
questionHtml:
"Ritas total bill at a restaurant was $25.00, including tax. If she left a tip of 20% of the total bill, what was the amount of the tip?",
choices: [
{ label: "A", text: "$3.50" },
{ label: "B", text: "$4.00" },
{ label: "C", text: "$4.50" },
{ label: "D", text: "$5.00" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The total bill was $25.00. The percentage 20% is equivalent to the decimal 0.2. The tip is the product of the percentage and the total bill; therefore, <strong>0 . 2 · 25 = 5</strong>, so the tip was $5.00.Choices A, B, and C are incorrect and may be the result of incorrectly converting the given percentage or a calculation error.",
hasFigure: false,
},
{
id: "77cf4fa6",
type: "spr",
questionHtml:
"There are <strong>170</strong> blocks in a container. Of these blocks, <strong>10 % sign</strong> are green. How many blocks in the container are green?",
choices: [],
correctAnswer: "17",
explanation:
"The correct answer is <strong>17</strong>. It's given that there are <strong>170</strong> blocks in a container, and of these blocks, <strong>10 % sign</strong> are green. Since <strong>10 % sign</strong> can be rewritten as <strong>(10) / (100)</strong>, or <strong>0.1</strong>, the number of green blocks in the container is <strong>0.1 (170)</strong>, or <strong>17</strong>.",
hasFigure: false,
},
{
id: "7ed0d098",
type: "mcq",
questionHtml:
"Lani spent 15% of her 8-hour workday in meetings. How many minutes of her workday did she spend in meetings?",
choices: [
{ label: "A", text: "1.2" },
{ label: "B", text: "15" },
{ label: "C", text: "48" },
{ label: "D", text: "72" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. There are 60 minutes in one hour, so an 8-hour workday has <strong>60 · 8 = 480</strong> minutes. To calculate 15% of 480, multiply 0.15 by 480: <strong>0 . 1 5 · 480 = 72</strong>. Therefore, Lani spent 72 minutes of her workday in meetings.Choice A is incorrect because 1.2 is 15% of 8, which gives the time Lani spent of her workday in meetings in hours, not minutes. Choices B and C are incorrect and may be the result of computation errors.",
hasFigure: false,
},
{
id: "8705ecba",
type: "mcq",
questionHtml:
"The cost of a certain shirt is $20 before a 5% sales tax is added. What is the total cost, including sales tax, to purchase the shirt?",
choices: [
{ label: "A", text: "$20.05" },
{ label: "B", text: "$20.50" },
{ label: "C", text: "$21.00" },
{ label: "D", text: "$25.00" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The total cost to purchase the shirt is the $20 cost of the shirt plus the 5% sales tax. The value of the 5% sales tax on the $20 shirt is equivalent to<strong>0 . 0 5 · 20 dollars</strong>, or $1. Therefore, the total cost to purchase the shirt is <strong>20 dollars + 1 dollar</strong>, or $21.Choice A is incorrect and may result from neglecting to multiply by $20 when finding the value of the sales tax. Choice B is incorrect and may result from dividing by 10, instead of by 100, and then neglecting to multiply by $20 when finding the sales tax. Choice D is incorrect and may result from interpreting the sales tax of 5% as $5.",
hasFigure: false,
},
{
id: "949cd96b",
type: "mcq",
questionHtml:
"The length of the base of a certain parallelogram is <strong>89 % sign</strong> of the height of the parallelogram. Which expression represents the length of the base of the parallelogram, where <strong>h</strong> is the height of the parallelogram?",
choices: [
{ label: "A", text: "<strong>89 h</strong>" },
{ label: "B", text: "<strong>0.089 h</strong>" },
{ label: "C", text: "<strong>8.9 h</strong>" },
{ label: "D", text: "<strong>0.89 h</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. It's given that the length of the base of the parallelogram is <strong>89 % sign</strong> of the height of the parallelogram. Since <strong>h</strong> is the height of the parallelogram, it follows that the length of the base of the parallelogram can be represented by the expression <strong>(89) / (100) h</strong>, or <strong>0.89 h</strong>.<br>Choice A is incorrect. This expression represents <strong>8, 900 % sign</strong>, not <strong>89 % sign</strong>, of the height of the parallelogram.<br>Choice B is incorrect. This expression represents <strong>8.9 % sign</strong>, not <strong>89 % sign</strong>, of the height of the parallelogram.<br>Choice C is incorrect. This expression represents <strong>890 % sign</strong>, not <strong>89 % sign</strong>, of the height of the parallelogram.",
hasFigure: false,
},
{
id: "9c44f828",
type: "mcq",
questionHtml:
"There are a total of <strong>840</strong> seats in a school auditorium. During an assembly, students occupied <strong>50 % sign</strong> of the seats in the auditorium. How many seats did the students occupy during this assembly?",
choices: [
{ label: "A", text: "<strong>25</strong>" },
{ label: "B", text: "<strong>50</strong>" },
{ label: "C", text: "<strong>420</strong>" },
{ label: "D", text: "<strong>790</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. It's given that during an assembly, students occupied <strong>50 % sign</strong> of the <strong>840</strong> seats in the school auditorium. Therefore, the number of seats that the students occupied during this assembly can be calculated by multiplying the number of seats in the school auditorium by <strong>(50) / (100)</strong>. Thus, the students occupied <strong>840 ((50) / (100))</strong>, or <strong>420</strong>, seats during this assembly.<br>Choice A is incorrect. This is approximately <strong>3 % sign</strong>, not <strong>50 % sign</strong>, of <strong>840</strong>.<br>Choice B is incorrect. This is approximately <strong>6 % sign</strong>, not <strong>50 % sign</strong>, of <strong>840</strong>.<br>Choice D is incorrect. This is approximately <strong>94 % sign</strong>, not <strong>50 % sign</strong>, of <strong>840</strong>.",
hasFigure: false,
},
{
id: "a8fabad0",
type: "mcq",
questionHtml:
"A waiter receives tips from each customer. On average, the tip is 15% of the customers bill. At this rate, which of the following is closest to the tip the waiter can expect when a customer has a bill that is $78.20?",
choices: [
{ label: "A", text: "$8.00" },
{ label: "B", text: "$10.00" },
{ label: "C", text: "$12.00" },
{ label: "D", text: "$14.00" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. If the bill is $78.20, 15% of the bill can be found by multiplying 78.20 by the decimal conversion of 15%, 78.20 × 0.15 = $11.73. The exact amount $11.73 is closest in value to $12.00.Choices A, B, and D are incorrect and may be the result of errors when calculating 15% of the total $78.20.",
hasFigure: false,
},
{
id: "bb7c8186",
type: "mcq",
questionHtml: "What is <strong>23 % sign</strong> of <strong>100</strong>?",
choices: [
{ label: "A", text: "<strong>23</strong>" },
{ label: "B", text: "<strong>46</strong>" },
{ label: "C", text: "<strong>77</strong>" },
{ label: "D", text: "<strong>123</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. <strong>23 % sign</strong> of <strong>100</strong> can be calculated by multiplying <strong>(23) / (100)</strong> by <strong>100</strong>, which yields <strong>((23) / (100)) 100</strong>, or <strong>23</strong>.<br>Choice B is incorrect. This is <strong>46 % sign</strong>, not <strong>23 % sign</strong>, of <strong>100</strong>.<br>Choice C is incorrect. This is <strong>23 % sign</strong> less than <strong>100</strong>, not <strong>23 % sign</strong> of <strong>100</strong>.<br>Choice D is incorrect. This is <strong>23 % sign</strong> greater than <strong>100</strong>, not <strong>23 % sign</strong> of <strong>100</strong>.",
hasFigure: false,
},
{
id: "bd90f87e",
type: "mcq",
questionHtml:
"What was the percent increase of the minimum wage from 1960 to 1970?",
choices: [
{ label: "A", text: "30%" },
{ label: "B", text: "60%" },
{ label: "C", text: "62.5%" },
{ label: "D", text: "120%" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. According to the table, the minimum wage in 1960 was $1.00 per hour, and in 1970 it was $1.60 per hour. The percentage change is therefore <strong>100 · (the fraction with numerator 1 . 6 0 1 . 0 0, and denominator 1 . 0 0, ) = 60 %</strong>.Choice A is incorrect and may result from averaging the two wages before calculating the percentage change. Choice C is incorrect. This is the 1960 wage expressed as a percentage of the 1970 wage, not the percentage change between the two. Choice D is incorrect and may result from a calculation error.",
hasFigure: false,
},
{
id: "e9fb7774",
type: "mcq",
questionHtml:
"What percentage of <strong>300</strong> is <strong>75</strong>?",
choices: [
{ label: "A", text: "<strong>25 % sign</strong>" },
{ label: "B", text: "<strong>50 % sign</strong>" },
{ label: "C", text: "<strong>75 % sign</strong>" },
{ label: "D", text: "<strong>225 % sign</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Let <strong>x</strong> represent the percentage of <strong>300</strong> that is <strong>75</strong>. This can be written as <strong>(x) / (100) (300) = 75</strong>, or <strong>3 x = 75</strong>. Dividing both sides of this equation by <strong>3</strong> yields <strong>x = 25</strong>. Therefore, <strong>25 % sign</strong> of <strong>300</strong> is <strong>75</strong>.<br>Choice B is incorrect. <strong>50 % sign</strong> of <strong>300</strong> is <strong>150</strong>, not <strong>75</strong>.<br>Choice C is incorrect. <strong>75 % sign</strong> of <strong>300</strong> is <strong>225</strong>, not <strong>75</strong>.<br>Choice D is incorrect. <strong>225 % sign</strong> of <strong>300</strong> is <strong>675</strong>, not <strong>75</strong>.",
hasFigure: false,
},
{
id: "eaab8bc1",
type: "spr",
questionHtml:
"Out of <strong>300</strong> seeds that were planted, <strong>80 % sign</strong> sprouted. How many of these seeds sprouted?",
choices: [],
correctAnswer: "240",
explanation:
"The correct answer is <strong>240</strong>. Its given that <strong>80 % sign</strong> of the <strong>300</strong> seeds sprouted. Therefore, the number of seeds that sprouted can be calculated by multiplying the number of seeds that were planted by <strong>(80) / (100)</strong>, which gives <strong>300 ((80) / (100))</strong>, or <strong>240</strong>.",
hasFigure: false,
},
];
export const PERCENTAGES_MEDIUM: PracticeQuestion[] = [
{
id: "121dc44f",
type: "mcq",
questionHtml:
"The population of City A increased by <strong>7 % sign</strong> from <strong>2015</strong> to <strong>2016</strong>. If the <strong>2016</strong> population is <strong>k</strong> times the <strong>2015</strong> population, what is the value of <strong>k</strong>?",
choices: [
{ label: "A", text: "<strong>0.07</strong>" },
{ label: "B", text: "<strong>0.7</strong>" },
{ label: "C", text: "<strong>1.07</strong>" },
{ label: "D", text: "<strong>1.7</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. It's given that the population of City A increased by <strong>7 % sign</strong> from <strong>20 15</strong> to <strong>20 16</strong>. Therefore, the population of City A in <strong>20 16</strong> includes <strong>100 % sign</strong> of the population of City A in <strong>20 15</strong> plus an additional <strong>7 % sign</strong> of the population of City A in <strong>20 15</strong>. This means that the population of City A in <strong>20 16</strong> is <strong>107 % sign</strong> of the population in <strong>20 15</strong>. Thus, the population of City A in <strong>20 16</strong> is <strong>(107) / (100)</strong>, or <strong>1.07</strong>, times the <strong>20 15</strong> population. Therefore, the value of <strong>k</strong> is <strong>1.07</strong>.<br>Choice A is incorrect. This would be the value of <strong>k</strong> if the population in <strong>20 16</strong> was <strong>7 % sign</strong> of the population in <strong>20 15</strong>.<br>Choice B is incorrect. This would be the value of <strong>k</strong> if the population in <strong>20 16</strong> was <strong>70 % sign</strong> of the population in <strong>20 15</strong>.<br>Choice D is incorrect. This would be the value of <strong>k</strong> if the population increased by <strong>70 % sign</strong>, not <strong>7 % sign</strong>, from <strong>20 15</strong> to <strong>20 16</strong>.",
hasFigure: false,
},
{
id: "566759ef",
type: "mcq",
questionHtml:
"Thomas installed a new stove in his restaurant. At the time of installation, the stove had a value of $800. Thomas estimates that each year the value of the stove will depreciate by 20% of the previous years estimated value. What is the estimated value of the stove exactly 2 years after Thomas installed it?",
choices: [
{ label: "A", text: "$480" },
{ label: "B", text: "$512" },
{ label: "C", text: "$556" },
{ label: "D", text: "$640" },
],
correctAnswer: "",
explanation:
"Choice B is correct. If the stoves value depreciates by 20% of the previous years estimated value, then each year it retains 100% 20% = 80%, or 0.80, of the previous years estimated value. Since the stoves value was $800 when Thomas installed it, the estimated value after two years would be (0.80)(0.80)($800) = $512.Choice A is incorrect. This is the value of the stove if each year it had depreciated by 20% of the original value rather than by 20% of the previous years estimated value. Choice C is incorrect and may be the result of a computational error. Choice D is incorrect. This is the estimated value of the stove 1 year after Thomas installed it, not 2 years.",
hasFigure: false,
},
{
id: "63573fea",
type: "mcq",
questionHtml:
"During the first month of sales, a company sold 1,300,000 units of a certain type of smartphone. During the same month, 15% of the units sold were returned. If sales and the return rate remain the same for each of the next 5 months, about how many units of this smartphone will be returned to the company during this 6-month period?",
choices: [
{ label: "A", text: "195,000" },
{ label: "B", text: "975,000" },
{ label: "C", text: "1,170,000" },
{ label: "D", text: "6,630,000" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Of the 1,300,000 units sold during the first month, 15% were returned, so <strong>1, 300, 000 · 0 . 1 5 = 195, 000</strong> units were returned during the first month. If the units were sold and returned at the same rate for the next 5 months, then a total of <strong>195, 000 · 6 = 1, 170, 000</strong> smartphone units were returned during the 6-month period.Choice A is incorrect. This is the number of units that were returned in 1 month. Choice B is incorrect. This is the number of units that were returned in 5 months. Choice D is incorrect. This is the number of units sold and not returned during the first 6 months.",
hasFigure: false,
},
{
id: "707db2d3",
type: "mcq",
questionHtml:
"For the finale of a TV show, viewers could use either social media or a text message to vote for their favorite of two contestants. The contestant receiving more than 50% of the vote won. An estimated 10% of the viewers voted, and 30% of the votes were cast on social media. Contestant 2 earned 70% of the votes cast using social media and 40% of the votes cast using a text message. Based on this information, which of the following is an accurate conclusion?",
choices: [
{
label: "A",
text: "If all viewers had voted, Contestant 2 would have won.",
},
{
label: "B",
text: "Viewers voting by social media were likely to be younger than viewers voting by text message.",
},
{
label: "C",
text: "If all viewers who voted had voted by social media instead of by text message, Contestant 2 would have won.",
},
{
label: "D",
text: "Viewers voting by social media were more likely to prefer Contestant 2 than were viewers voting by text message.",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. It is given that Contestant 2 earned 70% of the votes cast using social media and 40% of the votes cast using a text message. Based on this information, viewers voting by social media were more likely to prefer Contestant 2 than were viewers voting by text message.Choices A, B, and C are incorrect. There is not enough information about the viewers to reach these conclusions.",
hasFigure: false,
},
{
id: "709e04de",
type: "mcq",
questionHtml:
"The value of <strong>z</strong> is <strong>1.13</strong> times <strong>100</strong>. The value of <strong>z</strong> is what percent greater than <strong>100</strong>?",
choices: [
{ label: "A", text: "<strong>11.3</strong>" },
{ label: "B", text: "<strong>13</strong>" },
{ label: "C", text: "<strong>130</strong>" },
{ label: "D", text: "<strong>213</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that the value of <strong>z</strong> is <strong>1.13</strong> times <strong>100</strong>. This can be written as <strong>z = (1.13) (100)</strong>, which is equivalent to <strong>z = (1 + 0.13) (100)</strong>, or <strong>z = (1 + (13) / (100)) (100)</strong>. It follows that the value of <strong>z</strong> is <strong>100 % sign</strong> of <strong>100</strong> plus <strong>13 % sign</strong> of <strong>100</strong>. Therefore, the value of <strong>z</strong> is <strong>13 % sign</strong> greater than <strong>100</strong>.<br>Choice A is incorrect. This gives a value of <strong>z</strong> that is <strong>1.113</strong>, not <strong>1.13</strong>, times <strong>100</strong>.<br>Choice C is incorrect. This gives a value of <strong>z</strong> that is <strong>2.30</strong>, not <strong>1.13</strong>, times <strong>100</strong>.<br>Choice D is incorrect. This gives a value of <strong>z</strong> that is <strong>3.13</strong>, not <strong>1.13</strong>, times <strong>100</strong>.",
hasFigure: false,
},
{
id: "7b731fc3",
type: "spr",
questionHtml:
"What number is <strong>40 % sign</strong> greater than <strong>115</strong>?",
choices: [],
correctAnswer: "161",
explanation:
"The correct answer is <strong>161</strong>. For a number to be <strong>40 % sign</strong> greater than <strong>115</strong>, it follows that the number is <strong>(100 % sign of 115) + (40 % sign of 115)</strong>, which can be written as <strong>(100) / (100) (115) + (40) / (100) (115)</strong>. This expression is equivalent to <strong>1 (115) + 0.4 (115)</strong>, or <strong>1.4 (115)</strong>, which is equal to <strong>161</strong>. Therefore, <strong>161</strong> is <strong>40 % sign</strong> greater than <strong>115</strong>.",
hasFigure: false,
},
{
id: "7cab9fe1",
type: "mcq",
questionHtml:
"Which expression represents the result of increasing a positive quantity <strong>w</strong> by <strong>43 % sign</strong>?",
choices: [
{ label: "A", text: "<strong>1.43 w</strong>" },
{ label: "B", text: "<strong>0.57 w</strong>" },
{ label: "C", text: "<strong>43 w</strong>" },
{ label: "D", text: "<strong>0.43 w</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The result of increasing a positive quantity <strong>w</strong> by <strong>x % sign</strong> can be represented by the expression <strong>(1 + (x) / (100)) w</strong>. Therefore, the result of increasing a positive quantity <strong>w</strong> by <strong>43 % sign</strong> can be found by substituting <strong>43</strong> for <strong>x</strong> in the expression <strong>(1 + (x) / (100)) w</strong>, which gives <strong>(1 + (43) / (100)) w</strong>, or <strong>1.43 w</strong>. Thus, the expression <strong>1.43 w</strong> represents the result of increasing a positive quantity <strong>w</strong> by <strong>43 % sign</strong>.<br>Choice B is incorrect. This is the result of decreasing a positive quantity <strong>w</strong> by <strong>43 % sign</strong>.<br>Choice C is incorrect. This is the result of increasing a positive quantity <strong>w</strong> by <strong>4, 200 % sign</strong>.<br>Choice D is incorrect. This is the result of decreasing a positive quantity <strong>w</strong> by <strong>57 % sign</strong>.",
hasFigure: false,
},
{
id: "8a714fa1",
type: "mcq",
questionHtml:
"Which of the following represents the result of increasing the quantity x by 9%, where <strong>x > 0</strong> ?",
choices: [
{ label: "A", text: "<strong>1 . 0 9 x</strong>" },
{ label: "B", text: "<strong>0 . 0 9 x</strong>" },
{ label: "C", text: "<strong>x + 9</strong>" },
{ label: "D", text: "<strong>x + 0 . 0 9</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Increasing the positive quantity x by 9% is the result of adding 9% of x to x. 9% of x can be represented algebraically as <strong>the fraction, 9 over 100, end fraction · x</strong>, or <strong>0 . 0 9 x</strong>. Adding this expression to x yields <strong>x + 0 . 0 9 x</strong>, or <strong>1 . 0 9 x</strong>.Choice B is incorrect. This represents 9% of x. Choice C is incorrect. This represents increasing x by 9, not by 9%. Choice D is incorrect. This represents increasing x by 0.09, not by 9%.",
hasFigure: false,
},
{
id: "8cbf1415",
type: "mcq",
questionHtml:
"In a group, <em>(expression)</em>% of the items are red. Of all the red items in the group, <em>(expression)</em>% also have stripes. What percentage of the items in the group are red with stripes?",
choices: [
{ label: "A", text: "<em>(expression)</em>%" },
{ label: "B", text: "<em>(expression)</em>%" },
{ label: "C", text: "<em>(expression)</em>%" },
{ label: "D", text: "<em>(expression)</em>%" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that in a group, <strong>40 % sign</strong> of the items are red. It follows that the number of red items in the group can be represented by <strong>0 . 4 x</strong>, where <strong>x</strong> represents the total number of items in the group. Its also given that of all the red items in the group, <strong>30 % sign</strong> also have stripes. It follows that the number of items in the group that are red and have stripes can be represented by <strong>0 . 3 (0 . 4 x)</strong>, or <strong>0 . 12 x</strong>. The expression <strong>0 . 12 x</strong> represents <strong>12 % sign</strong> of <strong>x</strong>. Since <strong>x</strong> represents the total number of items in the group, it follows that <strong>12 % sign</strong> of the items in the group are red and have stripes.<br>Choice A is incorrect and may result from subtracting <strong>30 % sign</strong> from <strong>40 % sign</strong> rather than calculating <strong>30 % sign</strong> of <strong>40 % sign</strong>.<br>Choice C is incorrect and may result from adding <strong>30 % sign</strong> and <strong>40 % sign</strong> rather than calculating <strong>30 % sign</strong> of <strong>40 % sign</strong>.<br>Choice D is incorrect and may result from calculating the percentage that <strong>30 % sign</strong> is of <strong>40 % sign</strong> rather than calculating <strong>30 % sign</strong> of <strong>40 % sign</strong>.",
hasFigure: false,
},
{
id: "8e2e424e",
type: "mcq",
questionHtml:
"The number k is 36% greater than 50. If k is the product of 50 and r, what is the value of r ?",
choices: [
{ label: "A", text: "36" },
{ label: "B", text: "3.6" },
{ label: "C", text: "1.36" },
{ label: "D", text: "0.36" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that the number k is 36% greater than 50. Therefore, the value of k is the number 50 plus 36% of 50. This can be rewritten as <strong>k = 50 + the fraction 36 over 100, end fraction · 50</strong>. Multiplying the terms <strong>the fraction 36 over 100, end fraction · 50</strong> yields 18, so <strong>k = 50 + 18</strong>, or <strong>k = 68</strong>. Its also given that k is the product of 50 and r, which can be rewritten as <strong>k = 50 r</strong>. Substituting 68 for k yields <strong>68 = 50 r</strong>. Dividing both sides of this equation by 50 yields <strong>r = 1 . 3 6</strong>.Choice A is incorrect. This is the percentage that k is greater than 50. Choice B is incorrect and may result from a calculation error. Choice D is incorrect. This would be the value of r if k were 36% of 50, instead of 36% greater than 50.",
hasFigure: false,
},
{
id: "94c65646",
type: "spr",
questionHtml:
"<strong>432</strong> is <strong>96 % sign</strong> of what number?",
choices: [],
correctAnswer: "450",
explanation:
"The correct answer is <strong>450</strong>. Let <strong>x</strong> represent the number that <strong>432</strong> is <strong>96 % sign</strong> of. This can be written as <strong>((96) / (100)) x = 432</strong>, or <strong>0.96 x = 432</strong>. Dividing both sides of this equation by <strong>0.96</strong> yields <strong>x = 450</strong>. Therefore, <strong>432</strong> is <strong>96 % sign</strong> of <strong>450</strong>.",
hasFigure: false,
},
{
id: "96a45430",
type: "mcq",
questionHtml:
"A number n is increased 6%. If the result is 318, what is the value of n ?",
choices: [
{ label: "A", text: "199" },
{ label: "B", text: "299" },
{ label: "C", text: "300" },
{ label: "D", text: "337" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The decimal equivalent of 6% is 0.06. Since increasing the number n by 6% yields the number 318, this situation can be represented by the equation <strong>n · (1 + 0 . 0 6, ) = 318</strong>, or <strong>n · 1 . 0 6 = 318</strong>. Dividing both sides of this equation by 1.06 yields <strong>n = 300</strong>.Choice A is incorrect. This is the result when n is increased by 60%, not by 6%. Choice B is incorrect. This is the approximate result of decreasing 318 by 6%. Choice D is incorrect. This is the approximate result of increasing 318 by 6%.",
hasFigure: false,
},
{
id: "b2f6f17d",
type: "mcq",
questionHtml:
"A customers monthly water bill was $75.74. Due to a rate increase, her monthly bill is now $79.86. To the nearest tenth of a percent, by what percent did the amount of the customers water bill increase?",
choices: [
{ label: "A", text: "4.1%" },
{ label: "B", text: "5.1%" },
{ label: "C", text: "5.2%" },
{ label: "D", text: "5.4%" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. To find the percent increase of the customers water bill, the absolute increase of the bill, in dollars, is divided by the original amount of the bill, and the result is multiplied by 100%, as follows: <strong>the fraction with numerator 79 . 8 6 75 . 7 4, and denominator 75 . 7 4, is ≈, 0 . 0 5 4;</strong>; <strong>0 . 0 5 4 · 100 % = 5 . 4 %</strong>.Choice A is incorrect. This choice is the difference <strong>79 . 8 6 75 . 7 4</strong> rounded to the nearest tenth, which is the (absolute) increase of the bills amount, not its percent increase. Choice B is incorrect and may be the result of some calculation errors. Choice C is incorrect and is the result of dividing the difference between the two bill amounts by the new bill amount instead of the original bill amount.",
hasFigure: false,
},
{
id: "ba61d95f",
type: "mcq",
questionHtml:
"The population of Greenville increased by <strong>7 % sign</strong> from <strong>2015</strong> to <strong>2016</strong>. If the <strong>2016</strong> population is <strong>k</strong> times the <strong>2015</strong> population, what is the value of <strong>k</strong>?",
choices: [
{ label: "A", text: "<strong>0.07</strong>" },
{ label: "B", text: "<strong>0.7</strong>" },
{ label: "C", text: "<strong>1.07</strong>" },
{ label: "D", text: "<strong>1.7</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Let <strong>x</strong> be the 2015 population of Greenville. It's given that the population increased by <strong>7 % sign</strong> from 2015 to 2016. The increase in population can be written as <strong>(0.07) x</strong>. The 2016 population of Greenville is given as the sum of the 2015 population of Greenville and the increase in population from 2015 to 2016. This can be rewritten as <strong>x + (0.07) x</strong>, or <strong>1.07 x</strong>. Therefore, the value of <strong>k</strong> is <strong>1.07</strong>.<br>Choice A is incorrect. This is the percent, represented as a decimal, that the population increased from 2015 to 2016, not the value of <strong>k</strong>.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect. This is the value of <strong>k</strong> if the population increased by <strong>70 % sign</strong>, not <strong>7 % sign</strong>, from 2015 to 2016.",
hasFigure: false,
},
{
id: "d693f563",
type: "spr",
questionHtml:
"Last year, Cedric had <strong>35</strong> plants in his garden. This year, the number of plants in Cedrics garden is <strong>60 % sign</strong> greater than the number of plants in his garden last year. How many plants does Cedric have in his garden this year?",
choices: [],
correctAnswer: "56",
explanation:
"The correct answer is <strong>56</strong>. Its given that Cedric had <strong>35</strong> plants in his garden last year and that the number of plants in Cedric's garden this year is <strong>60 % sign</strong> greater than the number of plants in his garden last year. It follows that the number of plants in Cedrics garden this year is <strong>35</strong> plus <strong>60 % sign</strong> of <strong>35</strong>, which is equal to <strong>35 + 35 ((60) / (100))</strong>, or <strong>35 + 35 (0.6)</strong>. This expression is equivalent to <strong>35 + 21</strong>, or <strong>56</strong>. Therefore, Cedric has <strong>56</strong> plants in his garden this year.",
hasFigure: false,
},
{
id: "e9f4521a",
type: "spr",
questionHtml:
"<strong>13</strong> is <strong>p % sign</strong> of <strong>25</strong>. What is the value of <strong>p</strong>?",
choices: [],
correctAnswer: "52",
explanation:
"The correct answer is <strong>52</strong>. It's given that <strong>13</strong> is <strong>p % sign</strong> of <strong>25</strong>. It follows that <strong>(13) / (25) = (p) / (100)</strong>. Multiplying both sides of this equation by <strong>100</strong> gives <strong>52 = p</strong>. Therefore, the value of <strong>p</strong> is <strong>52</strong>.",
hasFigure: false,
},
];
export const PERCENTAGES_HARD: PracticeQuestion[] = [
{
id: "0231050d",
type: "spr",
questionHtml:
"<strong>The figure presents a line graph. The horizontal axis is labeled “Year, ” and the years 2003 through 2015 are indicated. The vertical axis is labeled “Annual snowfall, in inches, ” and the numbers 0 through 60, in increments of 10, are indicated. There are 13 points indicated on the graph. The data represented by the 13 points are as follows. Note that all values are approximate. Year, 2003. Number of inches, 40. Year, 2004. Number of inches, 12. Year, 2005. Number of inches, 13. Year, 2006. Number of inches, 14. Year, 2007. Number of inches, 10. Year, 2008. Number of inches, 5. Year, 2009. Number of inches, 8. Year, 2010. Number of inches, 56. Year, 2011. Number of inches, 10. Year, 2012. Number of inches, 3. Year, 2013. Number of inches, 4. Year, 2014. Number of inches, 32. Year, 2015. Number of inches, 19.</strong><br> <br><br>The line graph shows the total amount of snow, in inches, recorded each year in Washington, DC, from 2003 to 2015. If <strong>p %</strong> is the percent decrease in the annual snowfall from 2003 to 2007, what is the value of p ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 75. The percent decrease between two values is found by dividing the difference between the two values by the original value and multiplying by 100. The line graph shows that the annual snowfall in 2003 was 40 inches, and the annual snowfall in 2007 was 10 inches. Therefore, the percent decrease in the annual snowfall from 2003 to 2007 is <strong>(the fraction with numerator 40 10, and denominator 40, ) · 100</strong>, or 75. Its given that this is equivalent to <strong>p %</strong>, so the value of p is 75.",
hasFigure: true,
figureUrl: "/practice-images/0231050d_img1.png",
},
{
id: "040f2a84",
type: "spr",
questionHtml:
"The regular price of a shirt at a store is <strong>dollar sign 11.70</strong>. The sale price of the shirt is <strong>80 % sign</strong> less than the regular price, and the sale price is <strong>30 % sign</strong> greater than the store's cost for the shirt. What was the stores cost, in dollars, for the shirt? (Disregard the <strong>dollar sign</strong> sign when entering your answer. For example, if your answer is <strong>dollar sign 4.97</strong>, enter <strong>4.97</strong>)",
choices: [],
correctAnswer: "1.8, 9/5",
explanation:
"The correct answer is <strong>1.8</strong>. Its given that the regular price of a shirt at a store is <strong>dollar sign 11.70</strong>, and the sale price of the shirt is <strong>80 % sign</strong> less than the regular price. It follows that the sale price of the shirt is <strong>dollar sign 11.70 (1 (80) / (100))</strong>, or <strong>dollar sign 11.70 (1 0.8)</strong>, which is equivalent to <strong>dollar sign 2.34</strong>. Its also given that the sale price of the shirt is <strong>30 % sign</strong> greater than the stores cost for the shirt. Let <strong>x</strong> represent the stores cost for the shirt. It follows that <strong>2.34 = (1 + (30) / (100)) x</strong>, or <strong>2.34 = 1.3 x</strong>. Dividing both sides of this equation by <strong>1.3</strong> yields <strong>x = 1.80</strong>. Therefore, the stores cost, in dollars, for the shirt is <strong>1.80</strong>. Note that 1.8 and 9/5 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "0ea56bb2",
type: "mcq",
questionHtml:
"The manager of an online news service received the report above on the number of subscriptions sold by the service. The manager estimated that the percent increase from 2012 to 2013 would be double the percent increase from 2013 to 2014. How many subscriptions did the manager expect would be sold in 2014?",
choices: [
{ label: "A", text: "6,020" },
{ label: "B", text: "6,027" },
{ label: "C", text: "6,440" },
{ label: "D", text: "6,468" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The percent increase from 2012 to 2013 was <strong>the fraction with numerator 5, 880 5, 600, and denominator 5, 600 = 0 . 0 5</strong>, or 5%. Since the percent increase from 2012 to 2013 was estimated to be double the percent increase from 2013 to 2014, the percent increase from 2013 to 2014 was expected to be 2.5%.<br><br>Therefore, the number of subscriptions sold in 2014 is expected to be the number of subscriptions sold in 2013 multiplied by <strong>1 + 0 . 0 2 5</strong>, or <strong>5, 880 · 1 . 0 2 5 = 6, 027</strong>.Choice A is incorrect and is the result of adding half of the value of the increase from 2012 to 2013 to the 2013 result. Choice C is incorrect and is the result adding twice the value of the increase from 2012 to 2013 to the 2013 result. Choice D is incorrect and is the result of interpreting the percent increase from 2013 to 2014 as double the percent increase from 2012 to 2013.",
hasFigure: false,
},
{
id: "20845d36",
type: "spr",
questionHtml:
"The number <strong>a</strong> is <strong>70 % sign</strong> less than the positive number <strong>b</strong>. The number <strong>c</strong> is <strong>60 % sign</strong> greater than <strong>a</strong>. The number <strong>c</strong> is how many times <strong>b</strong>?",
choices: [],
correctAnswer: ".48, 12/25",
explanation:
"The correct answer is <strong>.48</strong>. It's given that the number <strong>a</strong> is <strong>70 % sign</strong> less than the positive number <strong>b</strong>. Therefore, <strong>a = (1 (70) / (100)) b</strong>, which is equivalent to <strong>a = (1 0.70) b</strong>, or <strong>a = 0.30 b</strong>. It's also given that the number <strong>c</strong> is <strong>60 % sign</strong> greater than <strong>a</strong>. Therefore, <strong>c = (1 + (60) / (100)) a</strong>, which is equivalent to <strong>c = (1 + 0.60) a</strong>, or <strong>c = 1.60 a</strong>. Since <strong>a = 0.30 b</strong>, substituting <strong>0.30 b</strong> for <strong>a</strong> in the equation <strong>c = 1.60 a</strong> yields <strong>c = 1.60 (0.30 b)</strong>, or <strong>c = 0.48 b</strong>. Thus, <strong>c</strong> is <strong>0.48</strong> times <strong>b</strong>. Note that .48 and 12/25 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "25faa756",
type: "spr",
questionHtml:
"The number <strong>a</strong> is <strong>60 % sign</strong> greater than the positive number <strong>b</strong>. The number <strong>c</strong> is <strong>45 % sign</strong> less than <strong>a</strong>. The number <strong>c</strong> is how many times <strong>b</strong>?",
choices: [],
correctAnswer: ".88, 22/25",
explanation:
"The correct answer is <strong>.88</strong>. Its given that the number <strong>a</strong> is <strong>60 % sign</strong> greater than the positive number <strong>b</strong>. Therefore, <strong>a = (1 + (60) / (100)) b</strong>, which is equivalent to <strong>a = (1 + 0.60) b</strong>, or <strong>a = 1.60 b</strong>. Its also given that the number <strong>c</strong> is <strong>45 % sign</strong> less than <strong>a</strong>. Therefore, <strong>c = (1 (45) / (100)) a</strong>, which is equivalent to <strong>c = (1 0.45) a</strong>, or <strong>c = 0.55 a</strong>. Since <strong>a = 1.60 b</strong>, substituting <strong>1.60 b</strong> for <strong>a</strong> in the equation <strong>c = 0.55 a</strong> yields <strong>c = 0.55 (1.60 b)</strong>, or <strong>c = 0.88 b</strong>. Thus, the number <strong>c</strong> is <strong>0.88</strong> times the number <strong>b</strong>. Note that .88 and 22/25 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "2e92cc21",
type: "spr",
questionHtml:
"The number <strong>a</strong> is <strong>110 % sign</strong> greater than the number <strong>b</strong>. The number <strong>b</strong> is <strong>90 % sign</strong> less than <strong>47</strong>. What is the value of <strong>a</strong>?",
choices: [],
correctAnswer: "9.87, 987/100",
explanation:
"The correct answer is <strong>9.87</strong>. Its given that the number <strong>a</strong> is <strong>110 % sign</strong> greater than the number <strong>b</strong>. It follows that <strong>a = (1 + (110) / (100)) b</strong>, or <strong>a = 2.1 b</strong>. Its also given that the number <strong>b</strong> is <strong>90 % sign</strong> less than <strong>47</strong>. It follows that <strong>b = (1 (90) / (100)) (47)</strong>, or <strong>b = 0.1 (47)</strong>, which yields <strong>b = 4.7</strong>. Substituting <strong>4.7</strong> for <strong>b</strong> in the equation <strong>a = 2.1 b</strong> yields <strong>a = 2.1 (4.7)</strong>, which is equivalent to <strong>a = 9.87</strong>. Therefore, the value of <strong>a</strong> is <strong>9.87</strong>.",
hasFigure: false,
},
{
id: "34f8cd89",
type: "mcq",
questionHtml:
"<strong>37 % sign</strong> of the items in a box are green. Of those, <strong>37 % sign</strong> are also rectangular. Of the green rectangular items, <strong>42 % sign</strong> are also metal. Which of the following is closest to the percentage of the items in the box that are not rectangular green metal items?",
choices: [
{ label: "A", text: "<strong>1.16 % sign</strong>" },
{ label: "B", text: "<strong>57.50 % sign</strong>" },
{ label: "C", text: "<strong>94.25 % sign</strong>" },
{ label: "D", text: "<strong>98.84 % sign</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. It's given that <strong>37 % sign</strong> of the items in a box are green. Let <strong>x</strong> represent the total number of items in the box. It follows that <strong>(37) / (100) x</strong>, or <strong>0.37 x</strong>, items in the box are green. It's also given that of those, <strong>37 % sign</strong> are also rectangular. Therefore, <strong>(37) / (100) (0.37 x)</strong>, or <strong>0.1369 x</strong>, items in the box are green rectangular items. It's also given that of the green rectangular items, <strong>42 % sign</strong> are also metal. Therefore, <strong>(42) / (100) (0.1369 x)</strong>, or <strong>0.057498 x</strong>, items in the box are rectangular green metal items. The number of the items in the box that are not rectangular green metal items is the total number of items in the box minus the number of rectangular green metal items in the box. Therefore, the number of items in the box that are not rectangular green metal items is <strong>x 0.057498 x</strong>, or <strong>0.942502 x</strong>. The percentage of items in the box that are not rectangular green metal items is the percentage that <strong>0.942502 x</strong> is of <strong>x</strong>. If <strong>p % sign</strong> represents this percentage, the value of <strong>p</strong> is <strong>100 ((0.942502 x) / (x))</strong>, or <strong>94.2502</strong>. Of the given choices, <strong>94.25 % sign</strong> is closest to the percentage of items in the box that are not rectangular green metal items.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "3d73a58b",
type: "spr",
questionHtml:
"A gift shop buys souvenirs at a wholesale price of <strong>7.00</strong> dollars each and resells them each at a retail price that is <strong>290 % sign</strong> of the wholesale price. At the end of the season, any remaining souvenirs are marked at a discounted price that is <strong>80 % sign</strong> off the retail price. What is the discounted price of each remaining souvenir, in dollars?",
choices: [],
correctAnswer: "203/50, 4.06",
explanation:
"The correct answer is <strong>4.06</strong>. It's given that the retail price is <strong>290 % sign</strong> of the wholesale price of <strong>dollar sign 7.00</strong>. Thus, the retail price is <strong>dollar sign 7.00 ((290) / (100))</strong>, which is equivalent to <strong>dollar sign 7.00 (2.9)</strong>, or <strong>dollar sign 20.30</strong>. It's also given that the discounted price is <strong>80 % sign</strong> off the retail price. Thus, the discounted price is <strong>dollar sign 20.30 (1 (80) / (100))</strong>, which is equivalent to <strong>dollar sign 20.30 (0.20)</strong>, or <strong>dollar sign 4.06</strong>.",
hasFigure: false,
},
{
id: "40e7a1a9",
type: "spr",
questionHtml:
"<strong>210</strong> is <strong>p % sign</strong> greater than <strong>30</strong>. What is the value of <strong>p</strong>?",
choices: [],
correctAnswer: "600",
explanation:
"The correct answer is <strong>600</strong>. Its given that <strong>210</strong> is <strong>p % sign</strong> greater than <strong>30</strong>. It follows that <strong>210 = (1 + (p) / (100)) (30)</strong>. Dividing both sides of this equation by <strong>30</strong> yields <strong>7 = 1 + (p) / (100)</strong>. Subtracting <strong>1</strong> from both sides of this equation yields <strong>6 = (p) / (100)</strong>. Multiplying both sides of this equation by <strong>100</strong> yields <strong>p = 600</strong>. Therefore, the value of <strong>p</strong> is <strong>600</strong>.",
hasFigure: false,
},
{
id: "55818046",
type: "mcq",
questionHtml:
"Which of the following is closest to the difference between the percentage of adults aged 1850 years who responded “warm” and the percentage of adults aged 51 years or greater who responded “warm”?",
choices: [
{ label: "A", text: "4%" },
{ label: "B", text: "5%" },
{ label: "C", text: "10%" },
{ label: "D", text: "18%" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The percentage of adults aged 1850 who responded “warm” is <strong>the fraction with numerator 295 + 246, and denominator 508 + 410, end fraction = the fraction 541 over 918</strong>, or about 58.9%. The percentage of adults aged 51 years or greater who responded “warm” is <strong>the fraction with numerator 238 + 137, and denominator 403 + 279, end fraction = the fraction 375 over 682</strong>, or about 55.0%. The difference between 58.9% and 55.0% is 3.9%. Of the answer choices, 4% is closest to this number.Choices B, C, and D are incorrect and may result from calculation errors.",
hasFigure: false,
},
{
id: "65c49824",
type: "spr",
questionHtml:
"A school district is forming a committee to discuss plans for the construction of a new high school. Of those invited to join the committee, 15% are parents of students, 45% are teachers from the current high school, 25% are school and district administrators, and the remaining 6 individuals are students. How many more teachers were invited to join the committee than school and district administrators?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 8. The 6 students represent <strong>(100 15 45 25, ), % = 15 %</strong> of those invited to join the committee. If x people were invited to join the committee, then <strong>0 . 1 5 x = 6</strong>. Thus, there were <strong>6 over, 0 . 1 5 = 40</strong> people invited to join the committee. It follows that there were <strong>0 . 4 5 · 40 = 18</strong> teachers and <strong>0 . 2 5 · 40 = 10</strong> school and district administrators invited to join the committee. Therefore, there were 8 more teachers than school and district administrators invited to join the committee.",
hasFigure: false,
},
{
id: "67c0200a",
type: "spr",
questionHtml:
"The number <strong>a</strong> is <strong>70 % sign</strong> less than the positive number <strong>b</strong>. The number <strong>c</strong> is <strong>80 % sign</strong> greater than <strong>a</strong>. The number <strong>c</strong> is how many times <strong>b</strong>?",
choices: [],
correctAnswer: ".54, 27/50",
explanation:
"The correct answer is <strong>.54</strong>. It's given that the number <strong>a</strong> is <strong>70 % sign</strong> less than the positive number <strong>b</strong>. Therefore, <strong>a = (1 (70) / (100)) b</strong>, which is equivalent to <strong>a = (1 0.70) b</strong>, or <strong>a = 0.30 b</strong>. It's also given that the number <strong>c</strong> is <strong>80 % sign</strong> greater than <strong>a</strong>. Therefore, <strong>c = (1 + (80) / (100)) a</strong>, which is equivalent to <strong>c = (1 + 0.80) a</strong>, or <strong>c = 1.80 a</strong>. Since <strong>a = 0.30 b</strong>, substituting <strong>0.30 b</strong> for <strong>a</strong> in the equation <strong>c = 1.80 a</strong> yields <strong>c = 1.80 (0.30 b)</strong>, or <strong>c = 0.54 b</strong>. Thus, <strong>c</strong> is <strong>0.54</strong> times <strong>b</strong>. Note that .54 and 27/50 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "8213b1b3",
type: "spr",
questionHtml:
"According to a set of standards, a certain type of substance can contain a maximum of <strong>0.001 % sign</strong> phosphorus by mass. If a sample of this substance has a mass of <strong>140</strong> grams, what is the maximum mass, in grams, of phosphorus the sample can contain to meet these standards?",
choices: [],
correctAnswer: ".0014",
explanation:
"The correct answer is <strong>.0014</strong>. It's given that a certain type of substance can contain a maximum of <strong>0.001 % sign</strong> phosphorus by mass to meet a set of standards. If a sample of the substance has a mass of <strong>140</strong> grams, it follows that the maximum mass, in grams, of phosphorus the sample can contain to meet the standards is <strong>0.001 % sign</strong> of <strong>140</strong>, or <strong>(0.001) / (100) (140)</strong>, which is equivalent to <strong>(0.00001) (140)</strong>, or <strong>0.0014</strong>. Note that .0014 and 0.001 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "8c5dbd3e",
type: "spr",
questionHtml:
"The number <strong>w</strong> is <strong>110 % sign</strong> greater than the number <strong>z</strong>. The number <strong>z</strong> is <strong>55 % sign</strong> less than <strong>50</strong>. What is the value of <strong>w</strong>?",
choices: [],
correctAnswer: "189/4, 47.25",
explanation:
"The correct answer is <strong>47.25</strong>. Its given that the number <strong>w</strong> is <strong>110 % sign</strong> greater than the number <strong>z</strong>. It follows that <strong>w = (1 + (110) / (100)) z</strong>, or <strong>w = 2.1 z</strong>. Its also given that the number <strong>z</strong> is <strong>55 % sign</strong> less than <strong>50</strong>. It follows that <strong>z = (1 (55) / (100)) (50)</strong>, or <strong>z = 0.45 (50)</strong>, which yields <strong>z = 22.5</strong>. Substituting <strong>22.5</strong> for <strong>z</strong> in the equation <strong>w = 2.1 z</strong> yields <strong>w = 2.1 (22.5)</strong>, which is equivalent to <strong>w = 47.25</strong>. Therefore, the value of <strong>w</strong> is <strong>47.25</strong>. Note that 47.25 and 189/4 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "954943a4",
type: "mcq",
questionHtml:
"Jennifer bought a box of Crunchy Grain cereal. The nutrition facts on the box state that a serving size of the cereal is <strong>three fourths</strong> cup and provides 210 calories, 50 of which are calories from fat. In addition, each serving of the cereal provides 180 milligrams of potassium, which is 5% of the daily allowance for adults. If p percent of an adults daily allowance of potassium is provided by x servings of Crunchy Grain cereal per day, which of the following expresses p in terms of x ?",
choices: [
{ label: "A", text: "<strong>p = 0 . 5 x</strong>" },
{ label: "B", text: "<strong>p = 5 x</strong>" },
{ label: "C", text: "<strong>p = (0 . 0 5, ), to the x power</strong>" },
{ label: "D", text: "<strong>p = (1 . 0 5, ), to the x power</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that each serving of Crunchy Grain cereal provides 5% of an adults daily allowance of potassium, so x servings would provide x times 5%. The percentage of an adults daily allowance of potassium, p, is 5 times the number of servings, x. Therefore, the percentage of an adults daily allowance of potassium can be expressed as <strong>p = 5 x</strong>.Choices A, C, and D are incorrect and may result from incorrectly converting 5% to its decimal equivalent, which isnt necessary since p is expressed as a percentage. Additionally, choices C and D are incorrect because the context should be represented by a linear relationship, not by an exponential relationship.",
hasFigure: false,
},
{
id: "ad911622",
type: "mcq",
questionHtml:
"The value of a collectible comic book increased by <strong>167 % sign</strong> from the end of <strong>2011</strong> to the end of <strong>2012</strong> and then decreased by <strong>16 % sign</strong> from the end of <strong>2012</strong> to the end of <strong>2013</strong>. What was the net percentage increase in the value of the collectible comic book from the end of <strong>2011</strong> to the end of <strong>2013</strong>?",
choices: [
{ label: "A", text: "<strong>124.28 % sign</strong>" },
{ label: "B", text: "<strong>140.28 % sign</strong>" },
{ label: "C", text: "<strong>151.00 % sign</strong>" },
{ label: "D", text: "<strong>209.72 % sign</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that the value of the comic book increased by <strong>167 % sign</strong> from the end of <strong>2011</strong> to the end of <strong>2012</strong>. Therefore, if the value of the comic book at the end of <strong>2011</strong> was <strong>x</strong> dollars, then the value, in dollars, of the comic book at the end of <strong>2012</strong> was <strong>x + ((167) / (100)) x</strong>, which can be rewritten as <strong>1 x + 1.67 x</strong>, or <strong>2.67 x</strong>. Its also given that the value of the comic book decreased by <strong>16 % sign</strong> from the end of <strong>2012</strong> to the end of <strong>2013</strong>. Therefore, the value, in dollars, of the comic book at the end of <strong>2013</strong> was <strong>2.67 x 2.67 x ((16) / (100))</strong>, which can be rewritten as <strong>2.67 x (2.67 x) (0.16)</strong>, or <strong>2.2428 x</strong>. Thus, if the value of the comic book at the end of <strong>2011</strong> was <strong>x</strong> dollars, and the value of the comic book at the end of <strong>2013</strong> was <strong>2.2428 x</strong> dollars, then from the end of <strong>2011</strong> to the end of <strong>2013</strong>, the value of the comic book increased by <strong>2.2428 x 1 x</strong>, or <strong>1.2428 x</strong>, dollars. Therefore, the increase in the value of the comic book from the end of <strong>2011</strong> to the end of <strong>2013</strong> is equal to <strong>1.2428</strong> times the value of the comic book at the end of <strong>2011</strong>. It follows that from the end of <strong>2011</strong> to the end of <strong>2013</strong>, the net percentage increase in the value of the comic book was <strong>(1.2428) (100) % sign</strong>, or <strong>124.28 % sign</strong>.<br>Choice B is incorrect and may result from conceptual or calculation errors. <br>Choice C is incorrect. This is the difference between the net percentage increase in the value of the comic book from the end of <strong>2011</strong> to the end of <strong>2012</strong> and the net percentage decrease in the value of the comic book from the end of <strong>2012</strong> to the end of <strong>2013</strong>, not the net percentage increase in the value of the comic book from the end of <strong>2011</strong> to the end of <strong>2013</strong>.<br>Choice D is incorrect. This is the net percentage increase in the value of the comic book from the end of <strong>2011</strong> to the end of <strong>2013</strong>, if the value of the comic book increased by <strong>167 % sign</strong> from the end of <strong>2011</strong> to the end of <strong>2012</strong> and then increased, not decreased, by <strong>16 % sign</strong> from the end of <strong>2012</strong> to the end of <strong>2013</strong>.",
hasFigure: false,
},
];

View File

@ -0,0 +1,548 @@
import { type PracticeQuestion } from "../../types/lesson";
export const PROBABILITY_EASY: PracticeQuestion[] = [
{
id: "12dbe3de",
type: "mcq",
questionHtml:
"A store received a shipment of 1,000 MP3 players, 4 of which were defective. If an MP3 player is randomly selected from this shipment, what is the probability that it is defective?",
choices: [
{ label: "A", text: "0.004" },
{ label: "B", text: "0.04" },
{ label: "C", text: "0.4" },
{ label: "D", text: "4" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The probability of randomly selecting a defective MP3 player from the shipment is equal to the number of defective MP3 players divided by the total number of MP3 players in the shipment. Therefore, the probability is <strong>4 over 1, 000</strong>, which is equivalent to 0.004.Choice B is incorrect because 0.04 represents 4 defective MP3 players out of 100 rather than out of 1,000. Choice C is incorrect because 0.4 represents 4 defective MP3 players out of 10 rather than out of 1,000. Choice D is incorrect. This is the number of defective MP3 players in the shipment.",
hasFigure: false,
},
{
id: "1353b86e",
type: "mcq",
questionHtml:
"The table shows the number of different colors of marbles in a bag. If a marble is chosen at random from the bag, what is the probability that the marble will be blue?",
choices: [
{ label: "A", text: "<strong>30 over 40</strong>" },
{ label: "B", text: "<strong>22 over 40</strong>" },
{ label: "C", text: "<strong>18 over 40</strong>" },
{ label: "D", text: "<strong>10 over 40</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. If a marble is chosen at random from the bag, the probability of choosing a marble of a certain color is the number of marbles of that color divided by the total number of marbles in the bag. Since there are 10 blue marbles in the bag, and there are 40 total marbles in the bag, the probability that the marble chosen will be blue is <strong>10 over 40</strong>.Choices A, B, and C are incorrect. These represent the probability that the marble chosen wont be blue (choice A), will be green (choice B), and wont be green (choice C).",
hasFigure: false,
},
{
id: "16cea46c",
type: "mcq",
questionHtml:
"A total of 25 men registered for singing lessons. The frequency table shows how many of these singers have certain voice types. If one of these singers is selected at random, what is the probability he is a baritone?",
choices: [
{ label: "A", text: "0.10" },
{ label: "B", text: "0.40" },
{ label: "C", text: "0.60" },
{ label: "D", text: "0.67" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. This probability is calculated by dividing the number of baritone singers by the total number of men registered for singing lessons. Its given that a total of 25 men registered for singing lessons and that there are 10 baritones. Therefore, the probability of selecting a baritone from this group at random is <strong>10 over 25</strong>, which is equivalent to 0.40.Choice A is incorrect. This would be the probability of selecting a baritone at random if there were 100 total men who registered for singing lessons. Choice C is incorrect. This is the probability of selecting a singer at random who isnt a baritone. Choice D is incorrect. This would be the probability of selecting a baritone at random if there were 15 total men registered for singing lessons.",
hasFigure: false,
},
{
id: "1dcea480",
type: "mcq",
questionHtml:
"A bag contains a total of 60 marbles. A marble is to be chosen at random from the bag. If the probability that a blue marble will be chosen is 0.35, how many marbles in the bag are blue?",
choices: [
{ label: "A", text: "21" },
{ label: "B", text: "25" },
{ label: "C", text: "35" },
{ label: "D", text: "39" },
],
correctAnswer: "",
explanation:
"Choice A is correct. Multiplying the number of marbles in the bag by the probability of selecting a blue marble gives the number of blue marbles in the bag. Since the bag contains a total of 60 marbles and the probability that a blue marble will be selected from the bag is 0.35, there are a total of <strong>0 . 3 5 · 60 = 21</strong> blue marbles in the bag.Choice B is incorrect and may result from subtracting 35 from 60. Choice C is incorrect. This would be the number of blue marbles in the bag if there were a total of 100 marbles, not 60 marbles. Choice D is incorrect. This is the number of marbles in the bag that arent blue.",
hasFigure: false,
},
{
id: "2a08d878",
type: "mcq",
questionHtml:
"There are n nonfiction books and 12 fiction books on a bookshelf. If one of these books is selected at random, what is the probability of selecting a nonfiction book, in terms of n ?",
choices: [
{ label: "A", text: "<strong>the fraction n over 12</strong>" },
{
label: "B",
text: "<strong>the fraction n over n + 12, end fraction</strong>",
},
{ label: "C", text: "<strong>the fraction 12 over n</strong>" },
{
label: "D",
text: "<strong>the fraction 12 over n + 12, end fraction</strong>",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. Since there are n nonfiction and 12 fiction books on the bookshelf, <strong>n + 12</strong> represents the total number of books. If one of these books is selected at random, the probability of selecting a nonfiction book is equivalent to the number of nonfiction books divided by the total number of books. Therefore, the probability of selecting a nonfiction book, in terms of n, is <strong>the fraction with numerator n, and denominator n + 12, end fraction</strong>.Choice A is incorrect. This expression represents the number of nonfiction books divided by the number of fiction books. Choice C is incorrect. This expression represents the number of fiction books divided by the number of nonfiction books. Choice D is incorrect. This expression represents the probability of selecting a fiction book.",
hasFigure: false,
},
{
id: "46545dd6",
type: "mcq",
questionHtml:
"The table above shows the number of students from two different high schools who completed summer internships in each of five years. No student attended both schools. Of the students who completed a summer internship in 2010, which of the following represents the fraction of students who were from Valley High School?",
choices: [
{ label: "A", text: "<strong>10 over 140</strong>" },
{ label: "B", text: "<strong>65 over 140</strong>" },
{ label: "C", text: "<strong>75 over 140</strong>" },
{ label: "D", text: "<strong>65 over 75</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. According to the table, 140 students from the two high schools completed summer internships in 2010. Of these, 65 were from Valley High School. Therefore, of the students who completed summer internships in 2010, <strong>the fraction 65 over 140</strong> represents the fraction who were from Valley High School.Choice A is incorrect. This is the difference between the numbers of students from the two high schools who completed internships in 2010 divided by the total number of students from the two schools who completed internships that year. Choice C is incorrect. This is the fraction of students from Foothill High School who completed internships out of all the students who completed internships in 2010. Choice D is incorrect. This is the number of students from Valley High School who completed internships in 2010 divided by the number of students from Foothill High School who completed internships in 2010.",
hasFigure: false,
},
{
id: "47624288",
type: "mcq",
questionHtml:
"The table gives the distribution of votes for a new school mascot and grade level for <strong>80</strong> students.<br><br>Mascot<br>Grade level<br><br>Sixth<br>Seventh<br>Eighth<br>Total<br><br>Badger<br><strong>4</strong><br><strong>9</strong><br><strong>9</strong><br><strong>22</strong><br><br>Lion<br><strong>9</strong><br><strong>2</strong><br><strong>9</strong><br><strong>20</strong><br><br>Longhorn<br><strong>4</strong><br><strong>6</strong><br><strong>4</strong><br><strong>14</strong><br><br>Tiger<br><strong>6</strong><br><strong>9</strong><br><strong>9</strong><br><strong>24</strong><br><br>Total<br><strong>23</strong><br><strong>26</strong><br><strong>31</strong><br><strong>80</strong><br><br>If one of these students is selected at random, what is the probability of selecting a student whose vote for new mascot was for a lion?",
choices: [
{ label: "A", text: "<strong>one ninth</strong>" },
{ label: "B", text: "<strong>one fifth</strong>" },
{ label: "C", text: "<strong>one fourth</strong>" },
{ label: "D", text: "<strong>two thirds</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. If one of these students is selected at random, the probability of selecting a student whose vote for the new mascot was for a lion is given by the number of votes for a lion divided by the total number of votes. The given table indicates that the number of votes for a lion is <strong>20</strong> votes, and the total number of votes is <strong>80</strong> votes. The table gives the distribution of votes for <strong>80</strong> students, and the table shows a total of 80 votes were counted. It follows that each of the <strong>80</strong> students voted exactly once. Thus, the probability of selecting a student whose vote for the new mascot was for a lion is <strong>(20) / (80)</strong>, or <strong>one fourth</strong>.<br>Choice A is incorrect and may result from conceptual or computational errors.<br>Choice B is incorrect and may result from conceptual or computational errors.<br>Choice D is incorrect and may result from conceptual or computational errors.",
hasFigure: false,
},
{
id: "4e527894",
type: "mcq",
questionHtml:
"There are <strong>20</strong> buttons in a bag: <strong>8</strong> white buttons, <strong>2</strong> orange buttons, and <strong>10</strong> brown buttons. If one of these buttons is selected at random, what is the probability of selecting a white button?",
choices: [
{ label: "A", text: "<strong>two twentieths</strong>" },
{ label: "B", text: "<strong>eight twentieths</strong>" },
{ label: "C", text: "<strong>(10) / (20)</strong>" },
{ label: "D", text: "<strong>(12) / (20)</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that there are <strong>20</strong> buttons in a bag and <strong>8</strong> of the buttons are white. If one button from the bag is selected at random, the probability of selecting a white button is the number of white buttons in the bag divided by the total number of buttons in the bag. Therefore, if one button from the bag is selected at random, the probability of selecting a white button is <strong>eight twentieths</strong>.<br>Choice A is incorrect. This is the probability of selecting an orange button from the bag.<br>Choice C is incorrect. This is the probability of selecting a brown button from the bag.<br>Choice D is incorrect. This is the probability of selecting a button that isn't white from the bag.",
hasFigure: false,
},
{
id: "60caadfd",
type: "mcq",
questionHtml:
"Each rock in a collection of <strong>70</strong> rocks was classified as either igneous, metamorphic, or sedimentary, as shown in the frequency table.<br><br>Classification<br>Frequency<br><br>igneous<br><strong>10</strong><br><br>metamorphic<br><strong>33</strong><br><br>sedimentary<br><strong>27</strong><br><br>If one of these rocks is selected at random, what is the probability of selecting a rock that is igneous?",
choices: [
{ label: "A", text: "<strong>(10) / (27)</strong>" },
{ label: "B", text: "<strong>(10) / (33)</strong>" },
{ label: "C", text: "<strong>(10) / (60)</strong>" },
{ label: "D", text: "<strong>(10) / (70)</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. If one of the rocks in the collection is selected at random, the probability of selecting a rock that is igneous is equal to the number of igneous rocks in the collection divided by the total number of rocks in the collection. According to the table, there are <strong>10</strong> igneous rocks in the collection, and it's given that there's a total of <strong>70</strong> rocks in the collection. Therefore, if one of the rocks in the collection is selected at random, the probability of selecting a rock that is igneous is <strong>(10) / (70)</strong>.<br>Choice A is incorrect. This is the number of igneous rocks in the collection divided by the number of sedimentary rocks in the collection, not divided by the total number of rocks in the collection.<br>Choice B is incorrect. This is the number of igneous rocks in the collection divided by the number of metamorphic rocks in the collection, not divided by the total number of rocks in the collection.<br>Choice C is incorrect. This is the number of igneous rocks in the collection divided by the number of rocks in the collection that aren't igneous, not divided by the total number of rocks in the collection.",
hasFigure: false,
},
{
id: "79201024",
type: "mcq",
questionHtml:
"A band with <strong>45</strong> members has <strong>11</strong> members who play saxophone. If one band member is selected at random, what is the probability of selecting a band member who plays saxophone?",
choices: [
{ label: "A", text: "<strong>one forty fifth</strong>" },
{ label: "B", text: "<strong>(11) / (45)</strong>" },
{ label: "C", text: "<strong>(34) / (45)</strong>" },
{ label: "D", text: "<strong>(45) / (45)</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The probability of an event occurring is the ratio of the number of favorable outcomes to the total number of possible outcomes. Its given that there are <strong>45</strong> band members, which is the total number of possible outcomes. It's also given that there are <strong>11</strong> band members who play saxophone. Therefore, the number of favorable outcomes is <strong>11</strong>. Thus, the probability of selecting a band member who plays saxophone is <strong>(11) / (45)</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect. This is the probability of selecting a band member who does not play saxophone.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "b680e76d",
type: "mcq",
questionHtml:
"How many of the males surveyed responded that they do not play a school sport?",
choices: [
{ label: "A", text: "109" },
{ label: "B", text: "252" },
{ label: "C", text: "468" },
{ label: "D", text: "688" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The table summarizes all 1,000 responses from the students surveyed. If 312 are males who play a sport, 220 are females who play a sport, and 216 are females who do not play a sport, then 1,000 312 220 216 = 252 males who do not play a sport.Choices A, C, and D are incorrect. If 109 males who do not play a sport responded, then the table summary would be 109 + 312 + 220 + 216 = 857 total student responses rather than 1,000. If 468 males who do not play a sport responded, then the table summary would be 468 + 312 + 220 + 216 = 1,216 total student responses rather than 1,000. If 688 males who do not play a sport responded, then the table summary would be 688 + 312 + 220 + 216 = 1,436 total student responses rather than 1,000.",
hasFigure: true,
figureUrl: "/practice-images/b680e76d_img1.png",
},
{
id: "b8150b17",
type: "mcq",
questionHtml:
"For a particular machine that produces beads, <strong>29</strong> out of every <strong>100</strong> beads it produces have a defect. A bead produced by the machine will be selected at random. What is the probability of selecting a bead that has a defect?",
choices: [
{ label: "A", text: "<strong>(1) / (2, 900)</strong>" },
{ label: "B", text: "<strong>one twenty ninth</strong>" },
{ label: "C", text: "<strong>(29) / (100)</strong>" },
{ label: "D", text: "<strong>(29) / (10)</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that <strong>29</strong> out of every <strong>100</strong> beads that the machine produces have a defect. It follows that if the machine produces <strong>k</strong> beads, then the number of beads that have a defect is <strong>(29) / (100) k</strong>, for some constant <strong>k</strong>. If a bead produced by the machine will be selected at random, the probability of selecting a bead that has a defect is given by the number of beads with a defect, <strong>(29) / (100) k</strong>, divided by the number of beads produced by the machine, <strong>k</strong>. Therefore, the probability of selecting a bead that has a defect is <strong>Start(StartFraction 29) / (100) k OverOver k EndEndFraction</strong>, or <strong>(29) / (100)</strong>.<br>Choice A is incorrect and may result from conceptual or computational errors.<br>Choice B is incorrect and may result from conceptual or computational errors.<br>Choice D is incorrect and may result from conceptual or computational errors.",
hasFigure: false,
},
{
id: "d89c1513",
type: "mcq",
questionHtml:
"Customer Purchases at a Gas Station<br> <br> Beverage purchased<br> Beverage not purchased<br> Total<br> Gasoline purchased<br> 60<br> 25<br> 85<br> Gasoline not purchased<br> 35<br> 15<br> 50<br> Total<br> 90<br> 40<br> 135<br> On Tuesday, a local gas station had 135 customers. The table above summarizes whether or not the customers on Tuesday purchased gasoline, a beverage, both, or neither. Based on the data in the table, what is the probability that a gas station customer selected at random on that day did not purchase gasoline?",
choices: [
{ label: "A", text: "<strong>15 over 50</strong>" },
{ label: "B", text: "<strong>15 over 40</strong>" },
{ label: "C", text: "<strong>35 over 50</strong>" },
{ label: "D", text: "<strong>50 over 135</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The total number of gas station customers on Tuesday was 135. The table shows that the number of customers who did not purchase gasoline was 50. Finding the ratio of the number of customers who did not purchase gasoline to the total number of customers gives the probability that a customer selected at random on that day did not purchase gasoline, which is <strong>50 over 135</strong>.Choice A is incorrect and may result from finding the probability that a customer did not purchase a beverage, given that the customer did not purchase gasoline. Choice B is incorrect and may result from finding the probability that a customer did not purchase gasoline, given that the customer did not purchase a beverage. Choice C is incorrect and may result from finding the probability that a customer did purchase a beverage, given that the customer did not purchase gasoline.",
hasFigure: false,
},
{
id: "e5b5fbdd",
type: "mcq",
questionHtml:
"Of the 8 planets in our solar system, 4 are considered rocky. If a student randomly selects 1 of those 8 planets as a topic for a report, what is the probability that the selected planet will be rocky?",
choices: [
{ label: "A", text: "<strong>one eighth</strong>" },
{ label: "B", text: "<strong>one fourth</strong>" },
{ label: "C", text: "<strong>one half</strong>" },
{ label: "D", text: "<strong>2</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. If one of these planets is selected at random, the probability that the selected planet will be rocky is calculated by dividing the number of planets that are considered rocky by the total number of planets. Its given that 4 of the 8 total planets are considered rocky. Therefore, the probability that the selected planet will be rocky is <strong>four eighths</strong>, which is equivalent to <strong>one half</strong>.Choices A and B are incorrect. These represent the probability if 1 of the 8 planets was considered rocky (choice A) and if 2 of the 8 planets were considered rocky (choice B). Choice D is incorrect and may result from dividing the total number of planets by the number of planets that are considered rocky.",
hasFigure: false,
},
{
id: "ec7b0eb8",
type: "mcq",
questionHtml:
"In a study of cell phone use, 799 randomly selected US teens were asked how often they talked on a cell phone and about their texting behavior. The data are summarized in the table above. If one of the 799 teens surveyed is selected at random, what is the probability that the teen talks on a cell phone daily?",
choices: [
{ label: "A", text: "<strong>1 over 799</strong>" },
{ label: "B", text: "<strong>415 over 799</strong>" },
{ label: "C", text: "<strong>384 over 415</strong>" },
{ label: "D", text: "<strong>384 over 799</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. If one of the teens surveyed is selected at random, the probability that the teen talks on a cell phone daily is equal to the quotient of the total number of teens who reported that they talk on a cell phone daily, 415, and the total number of teens surveyed, 799. Therefore, this probability is equal to <strong>415 over 799</strong>.Choice A is incorrect. This fraction represents the probability of selecting at random any one of the 799 teens surveyed. Choice C is incorrect and may result from conceptual errors. Choice D is incorrect. This fraction represents the probability of selecting at random one of the 799 teens surveyed who doesnt talk on a cell phone daily.",
hasFigure: false,
},
{
id: "eccbf957",
type: "mcq",
questionHtml:
"Each face of a fair <strong>14</strong>-sided die is labeled with a number from <strong>1</strong> through <strong>14</strong>, with a different number appearing on each face. If the die is rolled one time, what is the probability of rolling a <strong>2</strong>?",
choices: [
{ label: "A", text: "<strong>one fourteenth</strong>" },
{ label: "B", text: "<strong>two fourteenths</strong>" },
{ label: "C", text: "<strong>(12) / (14)</strong>" },
{ label: "D", text: "<strong>(13) / (14)</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The total number of possible outcomes for rolling a fair <strong>14</strong>-sided die is <strong>14</strong>. The number of possible outcomes for rolling a <strong>2</strong> is <strong>1</strong>. The probability of rolling a <strong>2</strong> is the number of possible outcomes for rolling a <strong>2</strong> divided by the total number of possible outcomes, or <strong>one fourteenth</strong>.<br>Choice B is incorrect. This is the probability of rolling a number no greater than <strong>2</strong>.<br>Choice C is incorrect. This is the probability of rolling a number greater than <strong>2</strong>.<br>Choice D is incorrect. This is the probability of rolling a number other than <strong>2</strong>.",
hasFigure: false,
},
];
export const PROBABILITY_MEDIUM: PracticeQuestion[] = [
{
id: "0301c5dc",
type: "mcq",
questionHtml:
"If one of these state parks is selected at random, what is the probability that it has camping facilities but does not have bicycle paths?",
choices: [
{ label: "A", text: "<strong>5 over 37</strong>" },
{ label: "B", text: "<strong>5 over 25</strong>" },
{ label: "C", text: "<strong>8 over 28</strong>" },
{ label: "D", text: "<strong>5 over 9</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The total number of state parks in the state is <strong>20 + 5 + 8 + 4 = 37</strong>. According to the table, 5 of these have camping facilities but not bicycle paths. Therefore, if a state park is selected at random, the probability that it has camping facilities but not bicycle paths is <strong>5 over 37</strong>.Choice B is incorrect. This is the probability that a state park selected at random from the state parks with camping facilities does not have bicycle paths. Choice C is incorrect. This is the probability that a state park selected at random from the state parks with bicycle paths does not have camping facilities. Choice D is incorrect. This is the probability that a state park selected at random from the state parks without bicycle paths does have camping facilities.",
hasFigure: false,
},
{
id: "0ae37ff3",
type: "mcq",
questionHtml:
"In a bag, there are <strong>7</strong> red, <strong>4</strong> white, <strong>33</strong> blue, and <strong>33</strong> yellow cubes. If one of these cubes is selected at random, what is the probability of selecting a cube that is neither blue nor yellow?",
choices: [
{ label: "A", text: "<strong>six sevenths</strong>" },
{ label: "B", text: "<strong>seven elevenths</strong>" },
{ label: "C", text: "<strong>one third</strong>" },
{ label: "D", text: "<strong>one seventh</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Its given that there are <strong>7</strong> red, <strong>4</strong> white, <strong>33</strong> blue, and <strong>33</strong> yellow cubes in the bag. Therefore, there are a total of <strong>7 + 4 + 33 + 33</strong>, or <strong>77</strong>, cubes in the bag. If the cube is neither blue nor yellow, then it must be either red or white. Therefore, the probability of selecting a cube that is neither blue nor yellow is equivalent to the probability of selecting a cube that is either red or white. If one of these cubes is selected at random, the probability of selecting a cube that is either red or white is equal to the sum of the number of red cubes and white cubes divided by the total number of cubes in the bag. There are <strong>7</strong> red cubes, <strong>4</strong> white cubes, and <strong>77</strong> total cubes in the bag. Therefore, the probability of selecting a red or white cube is <strong>(7 + 4) / (77)</strong>, which is equivalent to <strong>(11) / (77)</strong>, or <strong>one seventh</strong>. Thus, if one cube is selected at random, the probability of selecting a cube that is neither blue nor yellow is <strong>one seventh</strong>.<br>Choice A is incorrect. This is the probability of selecting a cube that is either blue or yellow, rather than the probability of selecting a cube that is neither blue nor yellow.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "2df8f293",
type: "spr",
questionHtml:
"Each vertex of a <strong>14</strong>-sided polygon is labeled with one of the <strong>14</strong> letters <strong>A</strong> through <strong>N</strong>, with a different letter at each vertex. If one vertex is selected at random, what is the probability that the letter <strong>D</strong> will be at the selected vertex? (Express your answer as a decimal or fraction, not as a percent.)",
choices: [],
correctAnswer: ".0714, 1/14",
explanation:
"The correct answer is <strong>one fourteenth</strong>. If one vertex of the polygon is selected at random, the probability that the letter <strong>D</strong> will be at the selected vertex is equal to the number of vertices labeled with the letter <strong>D</strong> divided by the total number of vertices. It's given that each vertex is labeled with one of the <strong>14</strong> letters <strong>A</strong> through <strong>N</strong>, with a different letter at each vertex. It follows that there is <strong>1</strong> vertex labeled with the letter <strong>D</strong>. It's also given that the polygon is <strong>14</strong>-sided. It follows that there are a total of <strong>14</strong> vertices. Thus, the probability that the letter <strong>D</strong> will be at the selected vertex is <strong>one fourteenth</strong>. Note that 1/14, .0714, and 0.071 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "30db8f77",
type: "spr",
questionHtml:
"At a conference, there are a total of <strong>275</strong> attendees. Each attendee is assigned to either group A, group B, or group C. If one of these attendees is selected at random, the probability of selecting an attendee who is assigned to group A is <strong>0.44</strong> and the probability of selecting an attendee who is assigned to group B is <strong>0.24</strong>. How many attendees are assigned to group C?",
choices: [],
correctAnswer: "88",
explanation:
"The correct answer is <strong>88</strong>. It's given that there are a total of <strong>275</strong> attendees and each attendee is assigned to either group A, group B, or group C. It's also given that if one of these attendees is selected at random, the probability of selecting an attendee who is assigned to group A is <strong>0.44</strong> and the probability of selecting an attendee who is assigned to group B is <strong>0.24</strong>. It follows that there are <strong>0.44 (275)</strong>, or <strong>121</strong>, attendees who are assigned to group A and <strong>0.24 (275)</strong>, or <strong>66</strong>, attendees who are assigned to group B. The number of attendees who are assigned to group C is the number of attendees who are not assigned to group A or group B. In other words, the number of attendees who are assigned to group C is the total number of attendees minus the number of attendees who are assigned to group A and group B. Therefore, the number of attendees who are assigned to group C is <strong>275 121 66</strong>, or <strong>88</strong>.",
hasFigure: false,
},
{
id: "38a9ac45",
type: "mcq",
questionHtml:
"If 1,200 customers register for new accounts at a social media website every day, what fraction of the first 60,000 new accounts are registered in the first 5 days?",
choices: [
{ label: "A", text: "<strong>one fifth</strong>" },
{ label: "B", text: "<strong>one tenth</strong>" },
{ label: "C", text: "<strong>one twelfth</strong>" },
{ label: "D", text: "<strong>1 over 50</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. If 1,200 customers register for new accounts every day, then (1,200)(5) = 6,000 customers registered for new accounts in the first 5 days. Therefore, of the first 60,000 new accounts that were registered, <strong>the fraction 6, 000 over 60, 000</strong>, or <strong>the fraction 1 over 10</strong>, were registered in the first 5 days.Choice A is incorrect. The fraction <strong>one fifth</strong> represents the fraction of accounts registered in 1 of the first 5 days. Choice C is incorrect and may result from conceptual or computation errors. Choice D is incorrect. The fraction <strong>1 over 50</strong> represents the fraction of the first 60,000 accounts that were registered in 1 day.",
hasFigure: false,
},
{
id: "46b2e169",
type: "spr",
questionHtml:
"A box contains <strong>13</strong> red pens and <strong>37</strong> blue pens. If one of these pens is selected at random, what is the probability of selecting a red pen? (Express your answer as a decimal or fraction, not as a percent.)",
choices: [],
correctAnswer: ".26, 13/50",
explanation:
"The correct answer is <strong>(13) / (50)</strong>. It's given that a box contains <strong>13</strong> red pens and <strong>37</strong> blue pens. If one of these pens is selected at random, the probability of selecting a red pen is the number of red pens in the box divided by the number of red and blue pens in the box. The number of red and blue pens in the box is <strong>13 + 37</strong>, or <strong>50</strong>. Since there are <strong>13</strong> red pens in the box, it follows that the probability of selecting a red pen is <strong>(13) / (50)</strong>. Note that 13/50 and .26 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "912cd125",
type: "mcq",
questionHtml:
"If one of the days on which there was no rain is selected at random, what is the probability the day was a weekend day?",
choices: [
{ label: "A", text: "<strong>the fraction 4 over 21</strong>" },
{ label: "B", text: "<strong>the fraction 1 over 4</strong>" },
{ label: "C", text: "<strong>the fraction 2 over 3</strong>" },
{ label: "D", text: "<strong>the fraction 3 over 4</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. There were 64 days with no rain. It was a weekend day for 16 of those 64 days. So 16 out of 64 of the days with no rain were weekend days. Because the day is selected at random, each day has an equal chance of being selected, so the probability is <strong>the fraction 16 over 64 = the fraction 1 over 4</strong>.<br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> Choice A is incorrect. It is the probability that a day selected at random from any one of the days during the 12 weeks is a weekend day with no rain. Choice C is incorrect. It is the probability that a day selected at random from the weekend days has no rain. Choice D is incorrect. It is the probability that a day selected at random from the days with no rain is a weekday.",
hasFigure: false,
},
{
id: "a3384df0",
type: "mcq",
questionHtml:
"The number of penguins in a zoo exhibit, sorted by gender and type of penguin, is shown in the table above. Which type of penguin has a female population that is the closest to being <strong>one-third</strong> of the total female penguin population in the exhibit?",
choices: [
{ label: "A", text: "Chinstrap" },
{ label: "B", text: "Emperor" },
{ label: "C", text: "Gentoo" },
{ label: "D", text: "Macaroni" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. It is given that there are 180 female penguins in the exhibit. Therefore, <strong>one third</strong> of the female penguins is <strong>one third · 180 = 60</strong> penguins. According to the table, there are 59 female chinstrap penguins, 27 female emperor penguins, 54 female gentoo penguins, and 40 female macaroni penguins. So the female chinstrap penguin population is the closest to 60, or <strong>one third</strong> of the total female population in the exhibit.Choices B, C, and D are incorrect and may result from reading data from the table incorrectly. Since the total female penguin population is 180, <strong>one third</strong> of the total female penguin population is 60. The numbers of female emperor (27), female gentoo (54), and female macaroni (40) penguins are not as close to 60 as the number of female chinstrap penguins (59).",
hasFigure: false,
},
{
id: "b1b5300b",
type: "mcq",
questionHtml:
"The table above shows information about 14 cars listed for sale on an auto dealerships website. If one of the cars listed for sale is selected at random, what is the probability that the car selected will be a hybrid car priced at no more than $25,000 ?",
choices: [
{ label: "A", text: "<strong>one seventh</strong>" },
{ label: "B", text: "<strong>two sevenths</strong>" },
{ label: "C", text: "<strong>one third</strong>" },
{ label: "D", text: "<strong>four sevenths</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that there are 2 hybrid cars priced at no more than $25,000. Its also given that there are 14 cars total for sale. Therefore, the probability of selecting a hybrid priced at no more than $25,000 when one car is chosen at random is <strong>2 over 14 = one seventh</strong>.Choice B is incorrect. This is the probability of selecting a hybrid car priced greater than $25,000 when choosing one car at random. Choice C is incorrect. This is the probability, when choosing randomly from only the hybrid cars, of selecting one priced at no more than $25,000. Choice D is incorrect. This is the probability of selecting a hybrid car when selecting at random from only the cars priced greater than $25,000.",
hasFigure: false,
},
{
id: "b6569d0e",
type: "mcq",
questionHtml:
"The table above gives the number of United States presidents from 1789 to 2015 whose age at the time they first took office is within the interval listed. Of those presidents who were at least 50 years old when they first took office, what fraction were at least 60 years old?",
choices: [
{ label: "A", text: "<strong>10 over 43</strong>" },
{ label: "B", text: "<strong>10 over 34</strong>" },
{ label: "C", text: "<strong>10 over 24</strong>" },
{ label: "D", text: "<strong>25 over 34</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The sample space is restricted to the presidents who were at least 50 years old when they first took office. Therefore, the sum of the values in the final four rows of the table, <strong>13 + 11 + 7 + 3 = 34</strong>, is the total number of presidents in the sample space. The number of presidents who were at least 60 years old is the sum of the values in the final two rows of the table: <strong>7 + 3 = 10</strong>. Thus, the fraction of the 34 presidents who were at least 50 years old when they first took office who were at least 60 years old is <strong>10 over 34</strong>.Choice A is incorrect. This is the fraction of all presidents in the table who were at least 60 years old when they first took office. Choice C is incorrect and may result from treating the number of presidents who were between 50 and 59 years old when they first took office, instead of the number of presidents who were at least 50 years old, as the sample space. Choice D is incorrect and may result from a calculation error.",
hasFigure: false,
},
{
id: "e1ad3d41",
type: "mcq",
questionHtml:
"The data on the coat color and eye color for 48 Himalayan kittens available for adoption were collected and summarized in the table above. What fraction of the chocolate-colored kittens has deep blue eyes?",
choices: [
{ label: "A", text: "<strong>the fraction 12 over 48</strong>" },
{ label: "B", text: "<strong>the fraction 12 over 28</strong>" },
{ label: "C", text: "<strong>the fraction 16 over 32</strong>" },
{ label: "D", text: "<strong>the fraction 12 over 16</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The table shows that there are a total of 16 kittens that have a chocolate-colored coat. Of the 16 with a chocolate-colored coat, 12 have deep blue eyes. Therefore, the fraction of chocolate-colored kittens with deep blue eyes is simply the ratio of those two numbers, or <strong>the fraction 12 over 16</strong>.Choice A is incorrect; this is the fraction of all chocolate-colored kittens. Choice B is incorrect; this is the fraction of kittens with deep blue eyes that have a chocolate-colored coat. Choice C is incorrect; this is the fraction of cream-tortoiseshell-colored kittens with deep blue eyes.",
hasFigure: false,
},
{
id: "e9ed719f",
type: "spr",
questionHtml:
"The table summarizes the distribution of color and shape for <strong>100</strong> tiles of equal area.<br><br> <br>Red<br>Blue<br>Yellow<br>Total<br><br>Square<br><strong>10</strong><br><strong>20</strong><br><strong>25</strong><br><strong>55</strong><br><br>Pentagon<br><strong>20</strong><br><strong>10</strong><br><strong>15</strong><br><strong>45</strong><br><br>Total<br><strong>30</strong><br><strong>30</strong><br><strong>40</strong><br><strong>100</strong><br><br>If one of these tiles is selected at random, what is the probability of selecting a red tile? (Express your answer as a decimal or fraction, not as a percent.)",
choices: [],
correctAnswer: ".3, 3/10",
explanation:
"The correct answer is <strong>three tenths</strong>. Its given that there are a total of <strong>100</strong> tiles of equal area, which is the total number of possible outcomes. According to the table, there are a total of <strong>30</strong> red tiles. The probability of an event occurring is the ratio of the number of favorable outcomes to the total number of possible outcomes. By definition, the probability of selecting a red tile is given by <strong>(30) / (100)</strong>, or <strong>three tenths</strong>. Note that 3/10 and .3 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "f8696cd8",
type: "mcq",
questionHtml:
"The table above shows the number of people who work in the Human Resources and Accounting departments of a company and the highest level of education they have completed. A person from one of these departments is to be chosen at random. If the person chosen works in the Human Resources department, what is the probability that the highest level of education the person completed is a masters degree?",
choices: [
{ label: "A", text: "<strong>the fraction 2 over 15</strong>" },
{ label: "B", text: "<strong>one-third</strong>" },
{ label: "C", text: "<strong>one-fourth</strong>" },
{ label: "D", text: "<strong>the fraction 8 over 15</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. In total, there are 6 people in the Human Resources department. Of those 6, 2 have a masters degree as their highest level of education. Therefore, the probability of an employee selected at random from the Human Resources department having a masters degree is  <strong>two sixths</strong>, which simplifies to <strong>one third</strong>.Choice A is incorrect; it is the probability that an employee selected at random from either department will be in the Human Resources department and have a masters degree. Choice C is incorrect; it is the probability that an employee with a masters degree selected at random will be in the Human Resources department. Choice D is incorrect; it is the probability that an employee selected at random from either department will have a masters degree.",
hasFigure: false,
},
];
export const PROBABILITY_HARD: PracticeQuestion[] = [
{
id: "585de39a",
type: "spr",
questionHtml:
"On May 10, 2015, there were 83 million Internet subscribers in Nigeria. The major Internet providers were MTN, Globacom, Airtel, Etisalat, and Visafone. By September 30, 2015, the number of Internet subscribers in Nigeria had increased to 97 million. If an Internet subscriber in Nigeria on September 30, 2015, is selected at random, the probability that the person selected was an MTN subscriber is 0.43. There were p million MTN subscribers in Nigeria on September 30, 2015. To the nearest integer, what is the value of p ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 42. Its given that in Nigeria on September 30, 2015, the probability of selecting an MTN subscriber from all Internet subscribers is 0.43, that there were p million, or <strong>p of 1, 000, 000</strong>, MTN subscribers, and that there were 97 million, or 97,000,000, Internet subscribers. The probability of selecting an MTN subscriber from all Internet subscribers can be found by dividing the number of MTN subscribers by the total number of Internet subscribers. Therefore, the equation <strong>the fraction with numerator p of 1, 000, 000, and denominator 97, 000, 000 = 0 . 4 3</strong> can be used to solve for p. Dividing 1,000,000 from the numerator and denominator of the expression on the left-hand side yields <strong>the fraction p over 97 = 0 . 4 3</strong>. Multiplying both sides of this equation by 97 yields <strong>p = 0 . 4 3 · 97, which = 41 . 7 1</strong>, which, to the nearest integer, is 42.",
hasFigure: false,
},
{
id: "5dc386fb",
type: "mcq",
questionHtml:
"To the nearest tenth of a percent, what percent of states with a state-level sales tax do not have a state-level income tax?",
choices: [
{ label: "A", text: "6.0%" },
{ label: "B", text: "12.0%" },
{ label: "C", text: "13.3%" },
{ label: "D", text: "14.0%" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The sum of the number of states with a state-level sales tax is <strong>39 + 6 = 45</strong>. Of these states, 6 dont have a state-level income tax. Therefore, <strong>6 over 45 = 0 . 1 3 3 3 dot dot dot</strong>, or about 13.3%, of states with a state-level sales tax dont have a state-level income tax.<br><br> Choice A is incorrect. This is the number of states that have a state-level sales tax and no state-level income tax. Choice B is incorrect. This is the percent of states that have a state-level sales tax and no state-level income tax. Choice D is incorrect. This is the percent of states that have no state-level income tax.",
hasFigure: false,
},
{
id: "6626cac3",
type: "spr",
questionHtml:
"PhoneEmailDinner dance55%80%Football game20%10%Picnic20%5%Pool party5%5%Total100%100%<br>An alumni association survey asked each high school graduate to select the one activity he or she preferred for the associations next event. Some of the people responded by phone, and the others responded by email. The table above shows the distribution of preferred activity, in percent, for each response type used. For the survey, the number of email responses was twice the number of phone responses. If a person who preferred a picnic is selected at random, what is the probability that the person responded by email?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is <strong>one third</strong>. Its given that the number of email responses is twice the number of phone responses. Therefore, if the number of phone responses is p, then the number of email responses is <strong>2 p</strong>. The table shows that 20% of people who responded by phone preferred a picnic. It follows that the expression <strong>0 . 2 0 p</strong> represents the number of these people. The table also shows that 5% of the people who responded by email preferred a picnic. The expression <strong>0 . 0 5 · 2 p</strong>, or <strong>0 . 1 p</strong>, represents the number of these people. Therefore, a total of <strong>0 . 2 0 p + 0 . 1 p</strong>, or <strong>0 . 3 p</strong> people preferred a picnic. Thus, the probability of selecting at random a person who responded by email from the people who preferred a picnic is <strong>the fraction 0 . 1 p over 0 . 3 p</strong>, or <strong>one third</strong>. Note that 1/3, .3333, and 0.333 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "6a715bed",
type: "spr",
questionHtml:
"The table summarizes the distribution of age and assigned group for <strong>90</strong> participants in a study.<br><br> <br><strong>0</strong><strong>9</strong> years<br><strong>10</strong><strong>19</strong> years<br><strong>20 +</strong> years<br>Total<br><br>Group A<br><strong>7</strong><br><strong>14</strong><br><strong>9</strong><br><strong>30</strong><br><br>Group B<br><strong>6</strong><br><strong>4</strong><br><strong>20</strong><br><strong>30</strong><br><br>Group C<br><strong>17</strong><br><strong>12</strong><br><strong>1</strong><br><strong>30</strong><br><br>Total<br><strong>30</strong><br><strong>30</strong><br><strong>30</strong><br><strong>90</strong><br><br>One of these participants will be selected at random. What is the probability of selecting a participant from group A, given that the participant is at least <strong>10</strong> years of age? (Express your answer as a decimal or fraction, not as a percent.)",
choices: [],
correctAnswer: ".3833, 23/60",
explanation:
"The correct answer is <strong>(23) / (60)</strong>. It's given that one of the participants will be selected at random. The probability of selecting a participant from group A given that the participant is at least <strong>10</strong> years of age is the number of participants in group A who are at least <strong>10</strong> years of age divided by the total number of participants who are at least <strong>10</strong> years of age. The table shows that in group A, there are <strong>14</strong> participants who are <strong>10</strong><strong>19</strong> years of age and <strong>9</strong> participants who are <strong>20 +</strong> years of age. Therefore, there are <strong>14 + 9</strong>, or <strong>23</strong>, participants in group A who are at least <strong>10</strong> years of age. The table also shows that there are a total of <strong>30</strong> participants who are <strong>10</strong><strong>19</strong> years of age and <strong>30</strong> participants who are <strong>20 +</strong> years of age. Therefore, there are a total of <strong>30 + 30</strong>, or <strong>60</strong>, participants who are at least <strong>10</strong> years of age. It follows that the probability of selecting a participant from group A given that the participant is at least <strong>10</strong> years of age is <strong>(23) / (60)</strong>. Note that 23/60, .3833, and 0.383 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "d4413871",
type: "spr",
questionHtml:
"Human blood can be classified into four common blood types—A, B, AB, and O. It is also characterized by the presence <strong>(+ )</strong> or absence <strong>( )</strong> of the rhesus factor. The table above shows the distribution of blood type and rhesus factor for a group of people. If one of these people who is rhesus negative <strong>( )</strong> is chosen at random, the probability that the person has blood type B is <strong>one ninth</strong> . What is the value of x ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 8. In this group, <strong>one ninth</strong> of the people who are rhesus negative have blood type B. The total number of people who are rhesus negative in the group is <strong>7 + 2 + 1 + x</strong>, and there are 2 people who are rhesus negative with blood type B. Therefore, <strong>the fraction with numerator 2, and denominator, 7 + 2 + 1 + x, end fraction = one ninth</strong>. Combining like terms on the left-hand side of the equation yields <strong>the fraction with numerator 2, and denominator, 10 + x, end fraction = one ninth</strong>. Multiplying both sides of this equation by 9 yields <strong>the fraction with numerator 18, and denominator, 10 + x, end fraction = 1</strong>, and multiplying both sides of this equation by <strong>(10 + x, )</strong> yields <strong>18 = 10 + x</strong>. Subtracting 10 from both sides of this equation yields <strong>8 = x</strong>.",
hasFigure: false,
},
{
id: "e29586d5",
type: "spr",
questionHtml:
"Number of Contestants by Score and Day 5 out<br>  of 54 out<br>  of 53 out<br>  of 52 out<br>  of 51 out<br>  of 50 out<br>  of 5TotalDay 123462320Day 223554120Day 333453220Total7913169660The same 20 contestants, on each of 3 days, answered 5 questions in order to win a prize. Each contestant received 1 point for each correct answer. The number of contestants receiving a given score on each day is shown in the table above.<br>No contestant received the same score on two different days. If a contestant is selected at random, what is the probability that the selected contestant received a score of 5 on Day 2 or Day 3, given that the contestant received a score of 5 on one of the three days?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is <strong>five sevenths</strong>. It is given that no contestant received the same score on two different days, so each of the contestants who received a score of 5 is represented in the “5 out of 5” column of the table exactly once. Therefore, the probability of selecting a contestant who received a score of 5 on Day 2 or Day 3, given that the contestant received a score of 5 on one of the three days, is found by dividing the total number of contestants who received a score of 5 on Day 2 or Day 3 <strong>2 + 3 = 5</strong> by the total number of contestants who received a score of 5, which is given in the table as 7. So the probability is <strong>five sevenths</strong>. Note that 5/7, .7142, .7143, and 0.714 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "ecd09c38",
type: "mcq",
questionHtml:
"If a caller last Monday who asked about his or her bill is selected at random, which of the following is closest to the probability that the customer also asked for repairs?",
choices: [
{ label: "A", text: "0.05" },
{ label: "B", text: "0.07" },
{ label: "C", text: "0.20" },
{ label: "D", text: "0.27" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. According to the table, a total of 671 customers asked about a bill. Of these, 48 also asked for repairs. Therefore, if a customer who asked about a bill is selected at random, the probability that the customer also asked for repairs is <strong>48 over 671 is ≈ 0 . 0 7</strong>.Choice A is incorrect. This is the probability that a customer selected at random from all customers who called on Monday both asked for repairs and asked about a bill. Choice C is incorrect. This is the probability that a customer selected at random from all customers who called on Monday asked for repairs, regardless of whether or not the customer asked about a bill. Choice D is incorrect. This is the probability that a customer selected at random from those who asked for repairs also asked about a bill.",
hasFigure: false,
},
];

View File

@ -0,0 +1,842 @@
import { type PracticeQuestion } from "../../types/lesson";
export const RATIOS_EASY: PracticeQuestion[] = [
{
id: "000259aa",
type: "mcq",
questionHtml:
"A group of monarch butterflies migrated from Chicago, Illinois, to Michoacán, Mexico, flying a total of 2,100 miles. It took a single butterfly in the group 120 days to travel this route one way. On average, how many miles did the butterfly travel per day?",
choices: [
{ label: "A", text: "0.057" },
{ label: "B", text: "0.729" },
{ label: "C", text: "17.5" },
{ label: "D", text: "24" },
],
correctAnswer: "",
explanation:
"Choice C is correct. If the butterfly traveled 2,100 miles in 120 days, then it traveled, on average, <strong>2, 100 miles over 120 days = 17 . 5</strong> miles per day.Choice A is incorrect. This is approximately the average amount of time, in days, it took the butterfly to fly one mile: <strong>120 days over 2, 100 miles = 0 . 0 5 7</strong> days per mile. Choice B is incorrect and may result from an arithmetic error. Choice D is incorrect. This is the number of hours in a day rather than the number of miles flown per day.",
hasFigure: false,
},
{
id: "06a152cd",
type: "mcq",
questionHtml:
"To make a bakerys signature chocolate muffins, a baker needs 2.5 ounces of chocolate for each muffin. How many pounds of chocolate are needed to make 48 signature chocolate muffins? (1 pound = 16 ounces)",
choices: [
{ label: "A", text: "7.5" },
{ label: "B", text: "10" },
{ label: "C", text: "50.5" },
{ label: "D", text: "120" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. If 2.5 ounces of chocolate are needed for each muffin, then the number of ounces of chocolate needed to make 48 muffins is <strong>48 · 2 . 5 = 120</strong> ounces. Since 1 pound = 16 ounces, the number of pounds that is equivalent to 120 ounces is<strong>120 over 16 = 7 . 5</strong> pounds. Therefore, 7.5 pounds of chocolate are needed to make the 48 muffins.Choice B is incorrect. If 10 pounds of chocolate were needed to make 48 muffins, then the total number of ounces of chocolate needed would be <strong>10 · 16 = 160</strong> ounces. The number of ounces of chocolate per muffin would then be<strong>160 over 48 = 3 . 3 3</strong> ounces per muffin, not 2.5 ounces per muffin. Choices C and D are also incorrect. Following the same procedures as used to test choice B gives 16.8 ounces per muffin for choice C and 40 ounces per muffin for choice D, not 2.5 ounces per muffin. Therefore, 50.5 and 120 pounds cannot be the number of pounds needed to make 48 signature chocolate muffins.",
hasFigure: false,
},
{
id: "15617f62",
type: "mcq",
questionHtml:
"The population density of Worthington is <strong>290</strong> people per square mile. Worthington has a population of <strong>92, 800</strong> people. What is the area, in square miles, of Worthington?",
choices: [
{ label: "A", text: "<strong>102, 400</strong>" },
{ label: "B", text: "<strong>93, 090</strong>" },
{ label: "C", text: "<strong>320</strong>" },
{ label: "D", text: "<strong>32</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that the population density of Worthington is <strong>290</strong> people per square mile and Worthington has a population of <strong>92, 800</strong> people. Therefore, the area of Worthington is <strong>92, 800 people ((1 square mile) / (290 people))</strong>, which is equivalent to <strong>(92, 800 square miles) / (290)</strong>, or <strong>320</strong> square miles.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "24ad9dcb",
type: "mcq",
questionHtml:
"The weight of an object on Venus is approximately <strong>the fraction 9 over 10</strong> of its weight on Earth. The weight of an object on Jupiter is approximately <strong>the fraction 23 over 10</strong> of its weight on Earth. If an object weighs 100 pounds on Earth, approximately how many more pounds does it weigh on Jupiter than it weighs on Venus?",
choices: [
{ label: "A", text: "90" },
{ label: "B", text: "111" },
{ label: "C", text: "140" },
{ label: "D", text: "230" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The weight of an object on Venus is approximately <strong>nine tenths</strong> of its weight on Earth. If an object weighs 100 pounds on Earth, then the objects weight on Venus is approximately <strong>nine tenths · 100 = 90</strong> pounds. The same objects weight on Jupiter is approximately <strong>twenty three tenths</strong> of its weight on Earth; therefore, the object weighs approximately <strong>twenty three tenths · 100 = 230</strong> pounds on Jupiter. The difference between the objects weight on Jupiter and the objects weight on Venus is approximately <strong>230 90 = 140</strong> pounds. Therefore, an object that weighs 100 pounds on Earth weighs 140 more pounds on Jupiter than it weighs on Venus.Choice A is incorrect because it is the weight, in pounds, of the object on Venus. Choice B is incorrect because it is the weight, in pounds, of an object on Earth if it weighs 100 pounds on Venus. Choice D is incorrect because it is the weight, in pounds, of the object on Jupiter.",
hasFigure: false,
},
{
id: "2cdefcb1",
type: "mcq",
questionHtml:
"What length, in centimeters, is equivalent to a length of <strong>51</strong> meters? <strong>(1 meter = 100 centimeters)</strong>",
choices: [
{ label: "A", text: "<strong>0.051</strong>" },
{ label: "B", text: "<strong>0.51</strong>" },
{ label: "C", text: "<strong>5, 100</strong>" },
{ label: "D", text: "<strong>51, 000</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Since <strong>1</strong> meter is equal to <strong>100</strong> centimeters, <strong>51</strong> meters is equal to <strong>51 meters ((100 centimeters) / (1 meter))</strong>, or <strong>5, 100</strong> centimeters. <br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from dividing, rather than multiplying, <strong>51</strong> by <strong>100</strong>.<br>Choice D is incorrect. This is the length, in millimeters rather than centimeters, that is equivalent to a length of <strong>51</strong> meters.",
hasFigure: false,
},
{
id: "2d16d62c",
type: "spr",
questionHtml:
"A special camera is used for underwater ocean research. When the camera is at a depth of <strong>58</strong> fathoms, what is the camera's depth in feet? <strong>(1 fathom = 6 feet)</strong>",
choices: [],
correctAnswer: "348",
explanation:
"The correct answer is <strong>348</strong>. It's given that <strong>1</strong> fathom is equivalent to <strong>6</strong> feet. Therefore, <strong>58</strong> fathoms is equivalent to <strong>(58 fathoms) ((6 feet) / (1 fathom))</strong>, or <strong>348</strong> feet. Thus, when the camera is at a depth of <strong>58</strong> fathoms, the camera's depth, in feet, is <strong>348</strong>.",
hasFigure: false,
},
{
id: "312ba47c",
type: "mcq",
questionHtml:
"In a box of pens, the ratio of black pens to red pens is <strong>8</strong> to <strong>1</strong>. There are <strong>40</strong> black pens in the box. How many red pens are in the box?",
choices: [
{ label: "A", text: "<strong>5</strong>" },
{ label: "B", text: "<strong>8</strong>" },
{ label: "C", text: "<strong>40</strong>" },
{ label: "D", text: "<strong>320</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that the ratio of black pens to red pens is <strong>8</strong> to <strong>1</strong>. Therefore, there are <strong>one eighth</strong> as many red pens as black pens in the box. Its also given that there are <strong>40</strong> black pens in the box. Therefore, the number of red pens is <strong>one eighth</strong> of the <strong>40</strong> black pens. Thus, the number of red pens is <strong>40 (one eighth)</strong>, or <strong>5</strong>.<br>Choice B is incorrect. This is the number of black pens in the box for every red pen.<br>Choice C is incorrect. This is the number of black pens in the box.<br>Choice D is incorrect. This is the number of red pens in the box if the ratio of black pens to red pens is <strong>1</strong> to <strong>8</strong>.",
hasFigure: false,
},
{
id: "3ac09984",
type: "mcq",
questionHtml:
"Marta has 7,500 pesos she will convert to US dollars using a currency exchange service. At this time, the currency exchange rate is 1 peso = 0.075 US dollars. The exchange service will charge Marta a 2% fee on the converted US dollar amount. How many US dollars will Marta receive from the currency exchange after the 2% fee is applied?",
choices: [
{ label: "A", text: "$551.25" },
{ label: "B", text: "$562.50" },
{ label: "C", text: "$5,625.00" },
{ label: "D", text: "$98,000.00" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. At the exchange rate of 1 peso = 0.075 US dollars, 7,500 pesos would be converted to 7,500 × 0.075 = $562.50. However, since Maria pays a 2% fee on the converted US dollar amount, she receives only (100 2)%, or 98%, of the converted US dollars, and 562.50 × 0.98 = $551.25.Choice B is incorrect. This is the number of US dollars Maria would receive if the exchange service did not charge a 2% fee. Choice C is incorrect and may result from a decimal point error made when calculating the conversion to US dollars and from not assessing the 2% fee. Choice D is incorrect and may result from reversing the units of the exchange rate.",
hasFigure: false,
},
{
id: "3c8fdc40",
type: "spr",
questionHtml:
"A printer produces posters at a constant rate of <strong>42</strong> posters per minute. At what rate, in posters per hour, does the printer produce the posters?",
choices: [],
correctAnswer: "2520",
explanation:
"The correct answer is <strong>2, 520</strong>. There are <strong>60</strong> minutes in one hour. At a rate of <strong>42</strong> posters per minute, the number of posters produced in one hour can be determined by <strong>((42 posters) / (1 minute)) ((60 minutes) / (1 hour))</strong>, which is <strong>2, 520</strong> posters per hour.",
hasFigure: false,
},
{
id: "3f236a64",
type: "mcq",
questionHtml:
"In the table above, the ratio of y to x for each ordered pair is constant. What is the value of k ?",
choices: [
{ label: "A", text: "28" },
{ label: "B", text: "36" },
{ label: "C", text: "80" },
{ label: "D", text: "160" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Since the ratio of y to x is constant for each ordered pair in the table, the first row can be used to determine that the ratio of y to x is 4 to 1. The proportion <strong>4 over 1 = k over 40</strong> can be used to solve for k. Multiplying each side of the equation by 40 yields <strong>160 = k</strong>.Choice A is incorrect. This is the value of y when the value of x is 7, not 40. Choice B is incorrect and may result from subtracting 4 from 40 instead of multiplying 40 by 4. Choice C is incorrect and may result from incorrectly setting up the proportion.",
hasFigure: false,
},
{
id: "3f5398a6",
type: "mcq",
questionHtml:
"For a person m miles from a flash of lightning, the length of the time interval from the moment the person sees the lightning to the moment the person hears the thunder is k seconds. The ratio of m to k can be estimated to be 1 to 5. According to this estimate, the person is how many miles from a flash of lightning if the time interval is 25 seconds?",
choices: [
{ label: "A", text: "10" },
{ label: "B", text: "9" },
{ label: "C", text: "6" },
{ label: "D", text: "5" },
],
correctAnswer: "",
explanation:
"Choice D is correct. Its given that the ratio of m to k is estimated to be 1 to 5. Therefore, when <strong>k = 25</strong>, the relationship between these ratios can be expressed by the proportion <strong>m over 25 = one fifth</strong>. Multiplying both sides of this equation by 25 yields <strong>m = 5</strong>.Choices A, B, and C are incorrect and may result from calculation errors.",
hasFigure: false,
},
{
id: "4347a032",
type: "mcq",
questionHtml:
"How many teaspoons are equivalent to <strong>44</strong> tablespoons? <strong>(3 teaspoons = 1 tablespoon)</strong>",
choices: [
{ label: "A", text: "<strong>47</strong>" },
{ label: "B", text: "<strong>88</strong>" },
{ label: "C", text: "<strong>132</strong>" },
{ label: "D", text: "<strong>176</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. It's given that <strong>3</strong> teaspoons is equivalent to <strong>1</strong> tablespoon. Therefore, <strong>44</strong> tablespoons is equivalent to <strong>(44 tablespoons) ((3 teaspoons) / (1 tablespoon))</strong>, or <strong>132</strong> teaspoons.<br>Choice A is incorrect. This is equivalent to approximately <strong>15.66</strong> tablespoons, not <strong>44</strong> tablespoons.<br>Choice B is incorrect. This is equivalent to approximately <strong>29.33</strong> tablespoons, not <strong>44</strong> tablespoons.<br>Choice D is incorrect. This is equivalent to approximately <strong>58.66</strong> tablespoons, not <strong>44</strong> tablespoons.",
hasFigure: false,
},
{
id: "551c52b9",
type: "mcq",
questionHtml:
"Tilly earns <strong>p</strong> dollars for every <strong>w</strong> hours of work. Which expression represents the amount of money, in dollars, Tilly earns for <strong>39 w</strong> hours of work?",
choices: [
{ label: "A", text: "<strong>39 p</strong>" },
{ label: "B", text: "<strong>(p) / (39)</strong>" },
{ label: "C", text: "<strong>p + 39</strong>" },
{ label: "D", text: "<strong>p 39</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that Tilly earns <strong>p</strong> dollars for every <strong>w</strong> hours of work. This can be represented by the proportion <strong>(p) / (w)</strong>. The amount of money, <strong>x</strong>, Tilly earns for <strong>39 w</strong> hours of work can be found by setting up the proportion <strong>(p) / (w) = (x) / (39 w)</strong>. This can be rewritten as <strong>39 p w = x w</strong>. Dividing both sides by <strong>w</strong> results in <strong>x = 39 p</strong>. <br>Choice B is incorrect. This is the amount of money Tilly earns in dollars per hour, not the amount of money Tilly earns for <strong>39 w</strong> hours of work.<br>Choice C is incorrect. This is the amount of money Tilly earns for <strong>w</strong> hours of work plus <strong>39</strong>, not the amount of money Tilly earns for <strong>39 w</strong> hours of work.<br>Choice D is incorrect. This is the amount of money Tilly earns for <strong>w</strong> hours of work minus <strong>39</strong>, not the amount of money Tilly earns for <strong>39 w</strong> hours of work.",
hasFigure: false,
},
{
id: "6310adbc",
type: "mcq",
questionHtml:
"The ratio of t to u is 1 to 2, and <strong>t = 10</strong>. What is the value of u ?",
choices: [
{ label: "A", text: "2" },
{ label: "B", text: "5" },
{ label: "C", text: "10" },
{ label: "D", text: "20" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Its given that the ratio of t to u is 1 to 2. Since <strong>t = 10</strong>, it follows that the ratio of 10 to u is also 1 to 2. The relationship between these ratios can be represented by the proportion <strong>10 over u = one half</strong>. Multiplying both sides of this equation by 2 and then by u yields <strong>20 = u</strong>.Choice A is incorrect. This is the value of u when <strong>t = 1</strong>. Choice B is incorrect. This would be the value of u if the ratio of t to u were 2 to 1. Choice C is incorrect. This is the value of t, not u.",
hasFigure: false,
},
{
id: "763e6769",
type: "mcq",
questionHtml:
"The ratio <strong>x</strong> to <strong>y</strong> is equivalent to the ratio <strong>12</strong> to <strong>t</strong>. When <strong>x = 156</strong>, what is the value of <strong>y</strong> in terms of <strong>t</strong>?",
choices: [
{ label: "A", text: "<strong>13 t</strong>" },
{ label: "B", text: "<strong>12 t</strong>" },
{ label: "C", text: "<strong>144 t</strong>" },
{ label: "D", text: "<strong>168 t</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. It's given that the ratio <strong>x</strong> to <strong>y</strong> is equivalent to the ratio <strong>12</strong> to <strong>t</strong>. This can be represented by <strong>(x) / (y) = (12) / (t)</strong>. Substituting <strong>156</strong> for <strong>x</strong> in this equation yields <strong>(156) / (y) = (12) / (t)</strong>. This can be rewritten as <strong>12 y = 156 t</strong>. Dividing both sides of this equation by <strong>12</strong> yields <strong>y = 13 t</strong>. Therefore, when <strong>x = 156</strong>, the value of <strong>y</strong> in terms of <strong>t</strong> is <strong>13 t</strong>.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "7cd1c6db",
type: "mcq",
questionHtml:
"An object travels at a constant speed of <strong>12</strong> centimeters per second. At this speed, what is the time, in seconds, that it would take for the object to travel <strong>108</strong> centimeters?",
choices: [
{ label: "A", text: "<strong>9</strong>" },
{ label: "B", text: "<strong>96</strong>" },
{ label: "C", text: "<strong>120</strong>" },
{ label: "D", text: "<strong>972</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. If the object travels <strong>108</strong> centimeters at a speed of <strong>12</strong> centimeters per second, the time of travel can be determined by dividing the total distance by the speed. This results in <strong>(108 centimeters) / (12 centimeters slash second)</strong>, which is <strong>9</strong> seconds.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "808f7d6c",
type: "mcq",
questionHtml:
"If <strong>t = 4 u</strong>, which of the following is equivalent to <strong>2 t</strong>?",
choices: [
{ label: "A", text: "<strong>8 u</strong>" },
{ label: "B", text: "<strong>2 u</strong>" },
{ label: "C", text: "<strong>u</strong>" },
{ label: "D", text: "<strong>one-half u</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that <strong>t = 4 u</strong>. Multiplying both sides of this equation by 2 yields <strong>2 t = 2 · 4 u</strong>, or <strong>2 t = 8 u</strong>.Choice B is incorrect and may result from dividing, instead of multiplying, the right-hand side of the equation by 2. Choices C and D are incorrect and may result from calculation errors.",
hasFigure: false,
},
{
id: "85b33aa8",
type: "mcq",
questionHtml:
"A fish swam a distance of <strong>5, 104</strong> yards. How far did the fish swim, in miles? <strong>(1 mile = 1, 760 yards)</strong>",
choices: [
{ label: "A", text: "<strong>0.3</strong>" },
{ label: "B", text: "<strong>2.9</strong>" },
{ label: "C", text: "<strong>3, 344</strong>" },
{ label: "D", text: "<strong>6, 864</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that the fish swam <strong>5, 104</strong> yards and that <strong>1</strong> mile is equal to <strong>1, 760</strong> yards. Therefore, the fish swam <strong>5, 104 yards ((1 mile) / (1, 760 yards))</strong>, which is equivalent to <strong>(5, 104) / (1, 760) miles</strong>, or <strong>2.9</strong> miles. <br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "86636d8f",
type: "spr",
questionHtml:
"A customer spent <strong>dollar sign 27</strong> to purchase oranges at <strong>dollar sign 3</strong> per pound. How many pounds of oranges did the customer purchase?",
choices: [],
correctAnswer: "9",
explanation:
"The correct answer is <strong>9</strong>. Its given that the customer spent <strong>dollar sign 27</strong> to purchase oranges at <strong>dollar sign 3</strong> per pound. Therefore, the number of pounds of oranges the customer purchased is <strong>dollar sign 27 ((1 pound) / (dollar sign 3))</strong>, or <strong>9</strong> pounds.",
hasFigure: false,
},
{
id: "99550621",
type: "mcq",
questionHtml:
"Makayla is planning an event in a 5,400-square-foot room. If there should be at least 8 square feet per person, what is the maximum number of people that could attend this event?",
choices: [
{ label: "A", text: "588" },
{ label: "B", text: "675" },
{ label: "C", text: "15,274" },
{ label: "D", text: "43,200" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that the event will be in a 5,400-square-foot room and that there should be at least 8 square feet per person. The maximum number of people that could attend the event can be found by dividing the total square feet in the room by the minimum number of square feet needed per person, which gives <strong>the fraction 5, 400 over 8 = 675</strong>.Choices A and C are incorrect and may result from conceptual or computational errors. Choice D is incorrect and may result from multiplying, rather than dividing, 5,400 by 8.",
hasFigure: false,
},
{
id: "aeeaec96",
type: "mcq",
questionHtml:
"How many yards are equivalent to <strong>612</strong> inches? <strong>(1 yard = 36 inches)</strong>",
choices: [
{ label: "A", text: "<strong>0.059</strong>" },
{ label: "B", text: "<strong>17</strong>" },
{ label: "C", text: "<strong>576</strong>" },
{ label: "D", text: "<strong>22, 032</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that <strong>1 yard = 36 inches</strong>. Therefore, <strong>612</strong> inches is equivalent to <strong>612 inches ((1 yard) / (36 inches))</strong>, which can be rewritten as <strong>(612 yards) / (36)</strong>, or <strong>17</strong> yards.<br>Choice A is incorrect. This is the number of yards that are equivalent to <strong>2.124</strong> inches.<br>Choice C is incorrect. This is the number of yards that are equivalent to <strong>20, 736</strong> inches.<br>Choice D is incorrect. This is the number of yards that are equivalent to <strong>793, 152</strong> inches.",
hasFigure: false,
},
{
id: "ba62b0b0",
type: "mcq",
questionHtml:
"A kangaroo has a mass of <strong>28</strong> kilograms. What is the kangaroo's mass, in grams? <strong>(1 kilogram = 1, 000 grams)</strong>",
choices: [
{ label: "A", text: "<strong>28, 000</strong>" },
{ label: "B", text: "<strong>1, 028</strong>" },
{ label: "C", text: "<strong>972</strong>" },
{ label: "D", text: "<strong>784</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. It's given that a kangaroo has a mass of <strong>28</strong> kilograms and that <strong>1</strong> kilogram is equal to <strong>1, 000</strong> grams. Therefore, the kangaroo's mass, in grams, is <strong>28 kilograms ((1, 000 grams) / (1 kilogram))</strong>, which is equivalent to <strong>28, 000</strong> grams.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "be35c117",
type: "mcq",
questionHtml:
"A wind turbine completes <strong>900</strong> revolutions in <strong>50</strong> minutes. At this rate, how many revolutions per minute does this turbine complete?",
choices: [
{ label: "A", text: "<strong>18</strong>" },
{ label: "B", text: "<strong>850</strong>" },
{ label: "C", text: "<strong>950</strong>" },
{ label: "D", text: "<strong>1, 400</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Dividing the number of revolutions by the number of minutes gives the number of revolutions the turbine completes per minute. Its given that the wind turbine completes <strong>900</strong> revolutions in <strong>50</strong> minutes. Therefore, at this rate, this turbine completes <strong>(900) / (50)</strong>, or <strong>18</strong>, revolutions per minute.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "d0d9ede4",
type: "spr",
questionHtml:
"How many feet are equivalent to <strong>34</strong> yards? <strong>(1 yard = 3 feet)</strong>",
choices: [],
correctAnswer: "102",
explanation:
"The correct answer is <strong>102</strong>. Its given that <strong>1</strong> yard is equivalent to <strong>3</strong> feet. Therefore, <strong>34</strong> yards is equivalent to <strong>(34 yards) ((3 feet) / (1 yard))</strong>, or <strong>102</strong> feet.",
hasFigure: false,
},
{
id: "e9841407",
type: "mcq",
questionHtml:
"Shaquan has 7 red cards and 28 blue cards. What is the ratio of red cards to blue cards that Shaquan has?",
choices: [
{ label: "A", text: "1 to 4" },
{ label: "B", text: "4 to 1" },
{ label: "C", text: "1 to 7" },
{ label: "D", text: "7 to 1" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that Shaquan has 7 red cards and 28 blue cards. Therefore, the ratio of red cards to blue cards that Shaquan has is 7 to 28. This ratio can be reduced by dividing both parts of the ratio by 7, which yields the ratio 1 to 4.Choice B is incorrect. This is the ratio of blue cards to red cards that Shaquan has. Choice C is incorrect and may result from a calculation error when reducing the ratio. Choice D is incorrect. This may result from finding the ratio of blue cards to red cards, or 28 to 7, and then making a calculation error when reducing the ratio.",
hasFigure: false,
},
{
id: "fe1ec415",
type: "mcq",
questionHtml:
"A cherry pitting machine pits <strong>12</strong> pounds of cherries in <strong>3</strong> minutes. At this rate, how many minutes does it take the machine to pit <strong>96</strong> pounds of cherries?",
choices: [
{ label: "A", text: "<strong>8</strong>" },
{ label: "B", text: "<strong>15</strong>" },
{ label: "C", text: "<strong>24</strong>" },
{ label: "D", text: "<strong>36</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. It's given that the cherry pitting machine pits <strong>12</strong> pounds of cherries in <strong>3</strong> minutes. This rate can be written as <strong>(12 pounds of cherries) / (3 minutes)</strong>. If the number of minutes it takes the machine to pit <strong>96</strong> pounds of cherries is represented by <strong>x</strong>, the value of <strong>x</strong> can be calculated by solving the equation <strong>(12 pounds of cherries) / (3 minutes) = (96 pounds of cherries) / (x minutes)</strong>, which can be rewritten as <strong>(12) / (3) = (96) / (x)</strong>, or <strong>4 = (96) / (x)</strong>. Multiplying each side of this equation by <strong>x</strong> yields <strong>4 x = 96</strong>. Dividing each side of this equation by <strong>4</strong> yields <strong>x = 24</strong>. Therefore, it takes the machine <strong>24</strong> minutes to pit <strong>96</strong> pounds of cherries.<br>Choice A is incorrect. This is the number of minutes it takes the machine to pit <strong>32</strong>, not <strong>96</strong>, pounds of cherries. <br>Choice B is incorrect. This is the number of minutes it takes the machine to pit <strong>60</strong>, not <strong>96</strong>, pounds of cherries. <br>Choice D is incorrect. This is the number of minutes it takes the machine to pit <strong>144</strong>, not <strong>96</strong>, pounds of cherries.",
hasFigure: false,
},
];
export const RATIOS_MEDIUM: PracticeQuestion[] = [
{
id: "1180401d",
type: "mcq",
questionHtml:
"The total area of a coastal city is 92.1 square miles, of which 11.3 square miles is water. If the city had a population of 621,000 people in the year 2010, which of the following is closest to the population density, in people per square mile of land area, of the city at that time?",
choices: [
{ label: "A", text: "6,740" },
{ label: "B", text: "7,690" },
{ label: "C", text: "55,000" },
{ label: "D", text: "76,000" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The land area of the coastal city can be found by subtracting the area of the water from the total area of the coastal city; that is, <strong>92 . 1 11 . 3 = 80 . 8</strong> square miles. The population density is the population divided by the land area, or <strong>the fraction 621, 000 over 80 . 8, end fraction = 7, 686</strong>, which is closest to 7,690 people per square mile.Choice A is incorrect and may be the result of dividing the population by the total area, instead of the land area. Choice C is incorrect and may be the result of dividing the population by the area of water. Choice D is incorrect and may be the result of making a computational error with the decimal place.",
hasFigure: false,
},
{
id: "181cc4d6",
type: "mcq",
questionHtml:
"Rectangle A has length 15 and width w. Rectangle B has length 20 and the same length-to-width ratio as rectangle A. What is the width of rectangle B in terms of w ?",
choices: [
{ label: "A", text: "<strong>four-thirds w</strong>" },
{ label: "B", text: "<strong>w + 5</strong>" },
{ label: "C", text: "<strong>three-fourths w</strong>" },
{ label: "D", text: "<strong>w 5</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that rectangle A has length 15 and width w. Therefore, the length-to-width ratio of rectangle A is 15 to w. Its also given that rectangle B has length 20 and the same length-to-width ratio as rectangle A. Let x represent the width of rectangle B. The proportion <strong>15 over w = 20 over x</strong> can be used to solve for x in terms of w. Multiplying both sides of this equation by x yields <strong>the fraction 15 x over w = 20</strong>, and then multiplying both sides of this equation by w yields <strong>15 x = 20 w</strong>. Dividing both sides of this equation by 15 yields <strong>x = the fraction 20 w over 15</strong>. Simplifying this fraction yields <strong>x = four thirds w</strong>.Choices B and D are incorrect and may result from interpreting the difference in the lengths of rectangle A and rectangle B as equivalent to the difference in the widths of rectangle A and rectangle B. Choice C is incorrect and may result from using a length-to-width ratio of w to 15, instead of 15 to w.",
hasFigure: false,
},
{
id: "3726e079",
type: "spr",
questionHtml:
"If <strong>(x) / (y) = 4</strong> and <strong>(24 x) / (n y) = 4</strong>, what is the value of <strong>n</strong>?",
choices: [],
correctAnswer: "24",
explanation:
"The correct answer is <strong>24</strong>. The equation <strong>(24 x) / (n y) = 4</strong> can be rewritten as <strong>((24) / (n)) ((x) / (y)) = 4</strong>. It's given that <strong>(x) / (y) = 4</strong>. Substituting <strong>4</strong> for <strong>(x) / (y)</strong> in the equation <strong>((24) / (n)) ((x) / (y)) = 4</strong> yields <strong>((24) / (n)) (4) = 4</strong>. Multiplying both sides of this equation by <strong>n</strong> yields <strong>(24) (4) = 4 n</strong>. Dividing both sides of this equation by <strong>4</strong> yields <strong>24 = n</strong>. Therefore, the value of <strong>n</strong> is <strong>24</strong>.",
hasFigure: false,
},
{
id: "445dd032",
type: "mcq",
questionHtml:
"Tanya earns $13.50 per hour at her part-time job. When she works z hours, she earns <strong>13 . 5 0 z</strong> dollars. Which of the following expressions gives the amount, in dollars, Tanya will earn if she works <strong>3 z</strong> hours?",
choices: [
{ label: "A", text: "<strong>3 · (13 . 5 0 z, )</strong>" },
{ label: "B", text: "<strong>3 + 13 . 5 0 z</strong>" },
{ label: "C", text: "<strong>3 z + 13 . 5 0 z</strong>" },
{ label: "D", text: "<strong>13 . 5 0 · (z + 3, )</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that when Tanya works z hours, she earns <strong>13 . 5 0 z</strong> dollars. Since her hourly rate is constant, if she works 3 times as many hours, or <strong>3 z</strong> hours, she will earn 3 times as many dollars, or <strong>3 · (13 . 5 0 z, )</strong>.Choice B is incorrect. This expression represents adding 3 dollars to the <strong>13 . 5 0 z</strong> dollars Tanya will earn. Choice C is incorrect. This expression can be rewritten as <strong>16 . 5 0 z</strong>, which implies that Tanya earns $16.50 per hour, not $13.50. Choice D is incorrect. This expression adds 3 to the number of hours Tanya works, rather than multiplying the hours she works by 3.",
hasFigure: false,
},
{
id: "51c9d65f",
type: "mcq",
questionHtml:
"For a certain rectangular region, the ratio of its length to its width is <strong>35</strong> to <strong>10</strong>. If the width of the rectangular region increases by <strong>7</strong> units, how must the length change to maintain this ratio?",
choices: [
{ label: "A", text: "It must decrease by <strong>24.5</strong> units." },
{ label: "B", text: "It must increase by <strong>24.5</strong> units." },
{ label: "C", text: "It must decrease by <strong>7</strong> units." },
{ label: "D", text: "It must increase by <strong>7</strong> units." },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that the ratio of the rectangular regions length to its width is <strong>35</strong> to <strong>10</strong>. This can be written as a proportion: <strong>(length) / (width) = (35) / (10)</strong>, or <strong>(script l) / (w) = (35) / (10)</strong>. This proportion can be rewritten as <strong>10 script l = 35 w</strong>, or <strong>script l = 3.5 w</strong>. If the width of the rectangular region increases by <strong>7</strong>, then the length will increase by some number <strong>x</strong> in order to maintain this ratio. The value of <strong>x</strong> can be found by replacing <strong>script l</strong> with <strong>script l + x</strong> and <strong>w</strong> with <strong>w + 7</strong> in the equation, which gives <strong>script l + x = 3.5 (w + 7)</strong>. This equation can be rewritten using the distributive property as <strong>script l + x = 3.5 w + 24.5</strong>. Since <strong>script l = 3.5 w</strong>, the right-hand side of this equation can be rewritten by substituting <strong>script l</strong> for <strong>3.5 w</strong>, which gives <strong>script l + x = script l + 24.5</strong>, or <strong>x = 24.5</strong>. Therefore, if the width of the rectangular region increases by <strong>7</strong> units, the length must increase by <strong>24.5</strong> units in order to maintain the given ratio.<br>Choice A is incorrect. If the width of the rectangular region increases, the length must also increase, not decrease.<br>Choice C is incorrect. If the width of the rectangular region increases, the length must also increase, not decrease.<br>Choice D is incorrect. Since the ratio of the length to the width of the rectangular region is <strong>35</strong> to <strong>10</strong>, if the width of the rectangular region increases by <strong>7</strong> units, the length would have to increase by a proportional amount, which would have to be greater than <strong>7</strong> units.",
hasFigure: false,
},
{
id: "61b87506",
type: "spr",
questionHtml:
"For the values <strong>j</strong> and <strong>k</strong>, the ratio of <strong>j</strong> to <strong>k</strong> is <strong>11</strong> to <strong>12</strong>. If <strong>j</strong> is multiplied by <strong>17</strong>, what is <strong>k</strong> multiplied by in order to maintain the same ratio?",
choices: [],
correctAnswer: "17",
explanation:
"The correct answer is <strong>17</strong>. If one value is multiplied by a number, then the other value must be multiplied by the same number in order to maintain the same ratio. Its given that <strong>j</strong> is multiplied by <strong>17</strong>. Therefore, in order to maintain the same ratio, <strong>k</strong> must also be multiplied by <strong>17</strong>.",
hasFigure: false,
},
{
id: "73ddfdac",
type: "spr",
questionHtml:
"A distance of <strong>112</strong> furlongs is equivalent to how many feet? <strong>(1 furlong = 220 yards and 1 yard = 3 feet)</strong>",
choices: [],
correctAnswer: "73920",
explanation:
"The correct answer is <strong>73, 920</strong>. It's given that <strong>1 furlong = 220 yards</strong> and <strong>1 yard = 3 feet</strong>. It follows that a distance of <strong>112</strong> furlongs is equivalent to <strong>(112 furlongs) ((220 yards) / (1 furlong)) ((3 feet) / (1 yard))</strong>, or <strong>73, 920</strong> feet.",
hasFigure: false,
},
{
id: "7e6c745f",
type: "mcq",
questionHtml:
"Food<br> Protein <br> Cost<br> 1 large egg<br> 6 grams<br> $0.36<br> 1 cup of milk<br> 8 grams<br> $0.24<br> <br> <br> The table above shows the amount of protein in two foods and the cost of each food. Based on the table, what is the ratio of the cost per gram of protein in a large egg to the cost per gram of protein in a cup of milk?",
choices: [
{ label: "A", text: "1 : 2" },
{ label: "B", text: "2 : 3" },
{ label: "C", text: "3 : 4" },
{ label: "D", text: "2 : 1" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The cost per gram of protein in 1 large egg is $0.36 ÷ 6 = $0.06. The cost per gram of protein in 1 cup of milk is $0.24 ÷ 8 = $0.03. It follows that the ratio of the cost per gram of protein in a large egg to the cost per gram of protein in a cup of milk is 0.06:0.03, which can be rewritten as 2:1.Choice A is incorrect and may result from finding the ratio of the cost per gram of protein in a cup of milk to the cost per gram of protein in a large egg (the reciprocal of the ratio specified in the question). Choices B and C are incorrect and may result from incorrectly calculating the unit rates or from errors made when simplifying the ratio.",
hasFigure: false,
},
{
id: "873d2838",
type: "spr",
questionHtml:
"The population density of Cedar County is <strong>230</strong> people per square mile. The county has a population of <strong>85, 100</strong> people. What is the area, in square miles, of Cedar County?",
choices: [],
correctAnswer: "370",
explanation:
"The correct answer is <strong>370</strong>. Its given that the population density of Cedar County is <strong>230</strong> people per square mile and the county has a population of <strong>85, 100</strong> people. Based on the population density, it follows that the area of Cedar County is <strong>(85, 100 people) ((1 square mile) / (230 people))</strong>, or <strong>370</strong> square miles.",
hasFigure: false,
},
{
id: "8917ce38",
type: "mcq",
questionHtml:
"Which of the following speeds is equivalent to 90 kilometers per hour? (1 kilometer = 1,000 meters)",
choices: [
{ label: "A", text: "25 meters per second" },
{ label: "B", text: "32 meters per second" },
{ label: "C", text: "250 meters per second" },
{ label: "D", text: "324 meters per second" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Since 1 kilometer is equal to 1,000 meters, it follows that 90 kilometers is equal to <strong>90 · 1, 000 = 90, 000</strong> meters. Since 1 hour is equal to 60 minutes and 1 minute is equal to 60 seconds, it follows that 1 hour is equal to <strong>60 · 60 = 3, 600</strong> seconds. Now <strong>the fraction 90 kilometers over 1 hour</strong> is equal to <strong>the fraction 90, 000 meters over 3, 600 seconds</strong>, which reduces to <strong>the fraction 25 meters over 1 second</strong> or 25 meters per second.Choices B, C, and D are incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "89c39d77",
type: "spr",
questionHtml:
"A competition consisted of four different events. One participant completed the first event with an average speed of <strong>20.300</strong> miles per hour. What was this average speed, in yards per hour? <strong>(1 mile = 1, 760 yards)</strong>",
choices: [],
correctAnswer: "35728",
explanation:
"The correct answer is <strong>35, 728</strong>. It's given that <strong>1 mile = 1, 760 yards</strong>. It follows that an average speed of <strong>20.300</strong> miles per hour is equivalent to <strong>((20.300 miles) / (1 hour)) ((1, 760 yards) / (1 mile))</strong>, or <strong>35, 728</strong> yards per hour.",
hasFigure: false,
},
{
id: "8e528129",
type: "spr",
questionHtml:
"Pure beeswax has a density of 0.555 ounce per cubic inch. An online company sells pure beeswax at a price of $8.00 per ounce. What is the selling price, in dollars per cubic inch, for pure beeswax purchased from this company?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 4.44. The selling price, in dollars per cubic inch, is found by multiplying the density, in ounces per cubic inch, by the unit price, in dollars per ounce: <strong>(0 . 5 5 5 ounce, over 1 cubic inch, ) · (8 dollars, over 1 ounce, )</strong> yields <strong>4 . 4 4 dollars over 1 cubic inch</strong>. Thus, the selling price, in dollars per cubic inch, is 4.44.",
hasFigure: false,
},
{
id: "939c46d1",
type: "mcq",
questionHtml:
"<strong>The figure presents a cylindrical shape with a circular base and a larger circular top. The diameter of the circular base is labeled “k over 2, ” the diameter of the circular top is labeled “k, ” and the height is labeled “k.” The volume of the figure = the fraction with numerator 7 π k³, and denominator 48</strong>The glass pictured above can hold a maximum volume of 473 cubic centimeters, which is approximately 16 fluid ounces. Jenny has a pitcher that contains 1 gallon of water. How many times could Jenny completely fill the glass with 1 gallon of water? <strong>1 gallon = 128 fluid ounces</strong>",
choices: [
{ label: "A", text: "16" },
{ label: "B", text: "8" },
{ label: "C", text: "4" },
{ label: "D", text: "3" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. It is given that the volume of the glass is approximately 16 fluid ounces. If Jenny has 1 gallon of water, which is 128 fluid ounces, she could fill the glass <strong>128 over 16, which = 8</strong> times.Choice A is incorrect because Jenny would need <strong>16 · 16</strong> fluid ounces = 256 fluid ounces, or 2 gallons, of water to fill the glass 16 times. Choice C is incorrect because Jenny would need only <strong>4 · 16</strong> fluid ounces = 64 fluid ounces of water to fill the glass 4 times. Choice D is incorrect because Jenny would need only <strong>3 · 16</strong> fluid ounces = 48 fluid ounces to fill the glass 3 times.",
hasFigure: true,
figureUrl: "/practice-images/939c46d1_img1.png",
},
{
id: "96c3e32d",
type: "spr",
questionHtml:
"One side of a flat board has an area of <strong>874</strong> square inches. If a pressure of <strong>19</strong> pounds per square inch of area is exerted on this side of the board, what is the total force, in pounds, exerted on this side of the board?",
choices: [],
correctAnswer: "16606",
explanation:
"The correct answer is <strong>16, 606</strong>. It's given that one side of a flat board has an area of <strong>874</strong> square inches. If a pressure of <strong>19</strong> pounds per square inch of area is exerted on this side of the board, the total force exerted on this side of the board is <strong>(874 square inches) ((19 pounds) / (1 square inch))</strong>, or <strong>16, 606</strong> pounds.",
hasFigure: false,
},
{
id: "b4912cc5",
type: "mcq",
questionHtml:
"The population density of Iceland, in people per square kilometer of land area, increased from 2.5 in 1990 to 3.3 in 2014. During this time period, the land area of Iceland was 100,250 square kilometers. By how many people did Icelands population increase from 1990 to 2014?",
choices: [
{ label: "A", text: "330,825" },
{ label: "B", text: "132,330" },
{ label: "C", text: "125,312" },
{ label: "D", text: "80,200" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The increase in Icelands population can be found by multiplying the increase in population density, in people per square kilometer, by the area, in square kilometers. Its given that the population density of Iceland was 2.5 people per square kilometer in 1990 and 3.3 people per square kilometer in 2014. The increase in population density can be found by subtracting 2.5 from 3.3, which yields 0.8. Its given that the land area of Iceland was 100,250 square kilometers. Thus, the increase in population is <strong>0 . 8 · 100, 250</strong>, or 80,200.Alternate approach: Its given that the population density of Iceland, in people per square kilometer of land area, in 1990 was 2.5. Since the land area of Iceland was 100,250 square kilometers, it follows that the population of Iceland in 1990 was <strong>2 . 5 · 100, 250</strong>, or 250,625. Similarly, the population of Iceland in 2014 was <strong>3 . 3 · 100, 250</strong>, or 330,825. The population increase is the difference in the population from 1990 to 2014, or <strong>330, 825 250, 625</strong>, which yields 80,200. Therefore, Icelands population increased by 80,200 from 1990 to 2014.<br>Choice A is incorrect. This is the population of Iceland in 2014. Choice B is incorrect and may result from dividing 3.3 by 2.5, instead of subtracting 2.5 from 3.3. Choice C is incorrect and may result from dividing the population of Iceland in 1990 by 2.",
hasFigure: false,
},
{
id: "cb4894f9",
type: "spr",
questionHtml:
"A triathlon is a multisport race consisting of three different legs. A triathlon participant completed the cycling leg with an average speed of <strong>19.700</strong> miles per hour. What was the average speed, in yards per hour, of the participant during the cycling leg? <strong>(1 mile = 1, 760 yards)</strong>",
choices: [],
correctAnswer: "34672",
explanation:
"The correct answer is <strong>34, 672</strong>. It's given that <strong>1 mile = 1, 760 yards</strong>. It follows that an average speed of <strong>19.700</strong> miles per hour is equivalent to <strong>((19.700 miles) / (1 hour)) ((1, 760 yards) / (1 mile))</strong>, or <strong>34, 672</strong> yards per hour.",
hasFigure: false,
},
{
id: "d28c29e1",
type: "mcq",
questionHtml:
"The International Space Station orbits Earth at an average speed of 4.76 miles per second. What is the space stations average speed in miles per hour?",
choices: [
{ label: "A", text: "285.6" },
{ label: "B", text: "571.2" },
{ label: "C", text: "856.8" },
{ label: "D", text: "17,136.0" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Since 1 minute = 60 seconds and 1 hour = 60 minutes, it follows that 1 hour = (60)(60), or 3,600 seconds. Using this conversion factor, the space stations average speed of 4.76 miles per second is equal to an average speed of <strong>the fraction with numerator 4 . 7 6 miles, and denominator second · the fraction with numerator 3, 600 seconds, and denominator hour = the fraction with numerator 17, 136 miles, and denominator hour</strong>, or 17,136 miles per hour.Choice A is incorrect. This is the space stations average speed in miles per minute. Choice B is incorrect. This is double the space stations average speed in miles per minute, or the number of miles the space station travels on average in 2 minutes. Choice C is incorrect. This is triple the space stations average speed in miles per minute, or the number of miles the space station travels on average in 3 minutes.",
hasFigure: false,
},
{
id: "e21d10a7",
type: "spr",
questionHtml:
"One of a planet's moons orbits the planet every <strong>252</strong> days. A second moon orbits the planet every <strong>287</strong> days. How many more days does it take the second moon to orbit the planet <strong>29</strong> times than it takes the first moon to orbit the planet <strong>29</strong> times?",
choices: [],
correctAnswer: "1015",
explanation:
"The correct answer is <strong>1, 015</strong>. Its given that the first moon orbits the planet every <strong>252</strong> days. Therefore, it takes the first moon <strong>252 (29)</strong>, or <strong>7, 308</strong>, days to orbit the planet <strong>29</strong> times. Its also given that the second moon orbits the planet every <strong>287</strong> days. Therefore, it takes the second moon <strong>287 (29)</strong>, or <strong>8, 323</strong>, days to orbit the planet <strong>29</strong> times. Since it takes the first moon <strong>7, 308</strong> days and the second moon <strong>8, 323</strong> days, it takes the second moon <strong>8, 323 7, 308</strong>, or <strong>1, 015</strong>, more days than it takes the first moon to orbit the planet <strong>29</strong> times.",
hasFigure: false,
},
{
id: "eb672707",
type: "spr",
questionHtml:
"How many tablespoons are equivalent to <strong>14</strong> teaspoons? <strong>(3 teaspoons = 1 tablespoon)</strong>",
choices: [],
correctAnswer: "14/3, 4.666, 4.667",
explanation:
"The correct answer is <strong>(14) / (3)</strong>. It's given that <strong>3</strong> teaspoons is equivalent to <strong>1</strong> tablespoon. Therefore, <strong>14</strong> teaspoons is equivalent to <strong>(14 teaspoons) ((1 tablespoon) / (3 teaspoons))</strong>, or <strong>(14) / (3)</strong> tablespoons. Note that 14/3, 4.666, and 4.667 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "ec787383",
type: "spr",
questionHtml:
"A distance of <strong>61</strong> furlongs is equivalent to how many feet? <strong>(1 furlong = 220 yards and 1 yard = 3 feet)</strong>",
choices: [],
correctAnswer: "40260",
explanation:
"The correct answer is <strong>40, 260</strong>. It's given that <strong>1 furlong = 220 yards</strong> and <strong>1 yard = 3 feet</strong>. It follows that a distance of <strong>61</strong> furlongs is equivalent to <strong>(61 furlongs) ((220 yards) / (1 furlong)) ((3 feet) / (1 yard))</strong>, or <strong>40, 260</strong> feet.",
hasFigure: false,
},
{
id: "f6cbb04a",
type: "mcq",
questionHtml:
"The equation above can be used to calculate the distance d, in miles, traveled by a car moving at a speed of 55 miles per hour over a period of t hours. For any positive constant k, the distance the car would have traveled after <strong>9 k</strong> hours is how many times the distance the car would have traveled after <strong>3 k</strong> hours?",
choices: [
{ label: "A", text: "<strong>3</strong>" },
{ label: "B", text: "<strong>6</strong>" },
{ label: "C", text: "<strong>3k</strong>" },
{ label: "D", text: "<strong>6 k</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Since the distance is equal to the amount of time multiplied by a constant, the given equation <strong>d = 55 t</strong> represents a proportional relationship between distance and time in this situation. Since <strong>9 k = 3 · 3 k</strong>, the time when <strong>t = 9 k</strong> hours is 3 times the time when <strong>t = 3 k</strong> hours. Therefore, the distance traveled after <strong>9 k</strong> hours is 3 times the distance after <strong>3 k</strong> hours.Choices B and D are incorrect and may result from interpreting the proportional relationship between time and distance as additive rather than multiplicative. Choice C is incorrect and may result from an arithmetic error.",
hasFigure: false,
},
{
id: "fea831fc",
type: "spr",
questionHtml:
"On April 18, 1775, Paul Revere set off on his midnight ride from Charlestown to Lexington. If he had ridden straight to Lexington without stopping, he would have traveled 11 miles in 26 minutes. In such a ride, what would the average speed of his horse have been, to the nearest tenth of a mile per hour?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 25.4. The average speed is the total distance divided by the total time. The total distance is 11 miles and the total time is 26 minutes. Thus, the average speed is <strong>11 over 26</strong> miles per minute. The question asks for the average speed in miles per hour, and there are 60 minutes in an hour; converting miles per minute to miles per hour gives the following:<strong>Average speed = the fraction 11 miles over 26 minutes, end fraction · the fraction 60 minutes over 1 hour, end fraction</strong><br> <strong>which = the fraction 660 over 26, end fraction, miles per hour</strong><br> <strong>which is ≈ 25 . 3 8 miles per hour</strong><br>Therefore, to the nearest tenth of a mile per hour, the average speed of Paul Reveres ride would have been 25.4 miles per hour. Note that 25.4 and 127/5 are examples of ways to enter a correct answer.",
hasFigure: false,
},
];
export const RATIOS_HARD: PracticeQuestion[] = [
{
id: "20b69297",
type: "mcq",
questionHtml:
"Anita created a batch of green paint by mixing 2 ounces of blue paint with 3 ounces of yellow paint. She must mix a second batch using the same ratio of blue and yellow paint as the first batch. If she uses 5 ounces of blue paint for the second batch, how much yellow paint should Anita use?",
choices: [
{ label: "A", text: "Exactly 5 ounces" },
{
label: "B",
text: "3 ounces more than the amount of yellow paint used in the first batch",
},
{
label: "C",
text: "1.5 times the amount of yellow paint used in the first batch",
},
{
label: "D",
text: "1.5 times the amount of blue paint used in the second batch",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. Its given that Anita used a ratio of 2 ounces of blue paint to 3 ounces of yellow paint for the first batch. For any batch of paint that uses the same ratio, the amount of yellow paint used will be <strong>three halves</strong>, or 1.5, times the amount of blue paint used in the batch. Therefore, the amount of yellow paint Anita will use in the second batch will be 1.5 times the amount of blue paint used in the second batch.Alternate approach: Its given that Anita used a ratio of 2 ounces of blue paint to 3 ounces of yellow paint for the first batch and that she will use 5 ounces of blue paint for the second batch. A proportion can be set up to solve for x, the amount of yellow paint she will use for the second batch: <strong>2 over 3 = 5 over x</strong>. Multiplying both sides of this equation by 3 yields <strong>2 = 15 over x</strong>, and multiplying both sides of this equation by x yields <strong>2 x = 15</strong>. Dividing both sides of this equation by 2 yields <strong>x = 7 . 5</strong>. Since Anita will use 7.5 ounces of yellow paint for the second batch, this is <strong>7 . 5 over 5 = 1 . 5</strong> times the amount of blue paint (5 ounces) used in the second batch.<br>Choices A, B, and C are incorrect and may result from incorrectly interpreting the ratio of blue paint to yellow paint used.",
hasFigure: false,
},
{
id: "3638f413",
type: "spr",
questionHtml:
"Jeremy deposited x dollars in his investment account on January 1, 2001. The amount of money in the account doubled each year until Jeremy had 480 dollars in his investment account on January 1, 2005. What is the value of x ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 30. The situation can be represented by the equation <strong>x · (2 to the fourth power, ) = 480</strong>, where the 2 represents the fact that the amount of money in the account doubled each year and the 4 represents the fact that there are 4 years between January 1, 2001, and January 1, 2005. Simplifying <strong>x · (2 to the fourth power, ) = 480</strong> gives <strong>16 x = 480</strong>. Therefore, <strong>x = 30</strong>.",
hasFigure: false,
},
{
id: "3f775bbf",
type: "mcq",
questionHtml:
"The table shows the distribution, by location and power capacity (maximum rate of power generation) of the twenty largest wind projects in the United States in 2013. The total power capacity of the nine wind projects located in Texas was 4,952 megawatts (MW), and the total power capacity of the twenty wind projects was 11,037 MW in 2013. The amount of energy produced in one hour at a rate of one megawatt is one megawatt-hour. If each of the nine Texas wind projects in 2013 had operated continuously for 24 hours at the maximum rate of power generation, approximately how many megawatt-hours of energy would the nine projects have produced?",
choices: [
{ label: "A", text: "200" },
{ label: "B", text: "5,000" },
{ label: "C", text: "11,000" },
{ label: "D", text: "120,000" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Its given that the total power capacity of the nine wind projects in Texas was 4,952 megawatts. Therefore, if all nine Texas projects operated continuously for 1 hour, the amount of energy produced would be 4,952 megawatt-hours. It follows that, if all nine Texas projects operated continuously for 24 hours, the amount of energy produced, in megawatt-hours, would be <strong>4, 952 · 24 = 118, 848</strong>, which is closest to 120,000.Choice A is incorrect. This is approximately the amount of energy produced for the nine projects divided by 24 hours. Choice B is incorrect. This is approximately the amount of energy produced for the nine projects. Choice C is incorrect. This is approximately the given amount of energy produced for all twenty projects in the table.",
hasFigure: false,
},
{
id: "69f6717f",
type: "mcq",
questionHtml:
"A sample of oak has a density of <strong>807</strong> kilograms per cubic meter. The sample is in the shape of a cube, where each edge has a length of <strong>0.90</strong> meters. To the nearest whole number, what is the mass, in kilograms, of this sample?",
choices: [
{ label: "A", text: "<strong>588</strong>" },
{ label: "B", text: "<strong>726</strong>" },
{ label: "C", text: "<strong>897</strong>" },
{ label: "D", text: "<strong>1, 107</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that the sample is in the shape of a cube with edge lengths of <strong>0.9</strong> meters. Therefore, the volume of the sample is <strong>0.90³</strong>, or <strong>0.729</strong>, cubic meters. Its also given that the sample has a density of <strong>807</strong> kilograms per <strong>1</strong> cubic meter. Therefore, the mass of this sample is <strong>0.729 cubic meters ((807 kilograms) / (1 cubic meter))</strong>, or <strong>588.303</strong> kilograms. Rounding this mass to the nearest whole number gives <strong>588</strong> kilograms. Therefore, to the nearest whole number, the mass, in kilograms, of this sample is <strong>588</strong>.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "7d721177",
type: "mcq",
questionHtml:
"The density of a certain type of wood is <em>(expression)</em> kilograms per cubic meter. A sample of this type of wood is in the shape of a cube and has a mass of <em>(expression)</em> kilograms. To the nearest hundredth of a meter, what is the length of one edge of this sample?",
choices: [
{ label: "A", text: "<em>(expression)</em>" },
{ label: "B", text: "<em>(expression)</em>" },
{ label: "C", text: "<em>(expression)</em>" },
{ label: "D", text: "<em>(expression)</em>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that the density of a certain type of wood is <strong>353</strong> kilograms per cubic meter <strong>(kg slash m³)</strong>, and a sample of this type of wood has a mass of <strong>345 kg</strong>. Let <strong>x</strong> represent the volume, in <strong>m³</strong>, of the sample. It follows that the relationship between the density, mass, and volume of this sample can be written<br>as <strong>(353 kg) / (1 m³) = (345 kg) / (x m³)</strong>, or <strong>353 = (345) / (x)</strong>. Multiplying both sides of this equation by <strong>x</strong> yields <strong>353 x = 345</strong>. Dividing both sides of this equation by <strong>353</strong> yields <strong>x = (345) / (353)</strong>. Therefore, the volume of this sample is <strong>(345) / (353) m³</strong>. Since its given that the sample of this type of wood is a cube, it follows that the length of one edge of this sample can be found using the volume formula for a cube, <strong>V = s³</strong>, where <strong>V</strong> represents the volume, in <strong>m³</strong>, and <strong>s</strong> represents the length, in m, of one edge of the cube. Substituting <strong>(345) / (353)</strong>for <strong>V</strong> in this formula yields <strong>(345) / (353) = s³</strong>. Taking the cube root of both sides of this equation yields <strong>RootIndex 3 √((345) / (353)) = s</strong>, or <strong>s almost = 0 . 99</strong>. Therefore, the length of one edge of this sample to the nearest hundredth of a meter is <strong>0.99</strong>.<br>Choices A, C, and D are incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "8637294f",
type: "spr",
questionHtml:
"If <strong>(4 a) / (b) = 6.7</strong> and <strong>(a) / (b n) = 26.8</strong>, what is the value of <strong>n</strong>?",
choices: [],
correctAnswer: ".0625, 1/16",
explanation:
"The correct answer is <strong>.0625</strong>. It's given that <strong>(4 a) / (b) = 6.7</strong> and <strong>(a) / (b n) = 26.8</strong>. The equation <strong>(4 a) / (b) = 6.7</strong> can be rewritten as <strong>(4) ((a) / (b)) = 6.7</strong>. Dividing both sides of this equation by <strong>4</strong> yields <strong>(a) / (b) = 1.675</strong>. The equation <strong>(a) / (b n) = 26.8</strong> can be rewritten as <strong>((a) / (b)) ((1) / (n)) = 26.8</strong>. Substituting <strong>1.675</strong> for <strong>(a) / (b)</strong> in this equation yields <strong>(1.675) ((1) / (n)) = 26.8</strong>, or <strong>(1.675) / (n) = 26.8</strong>. Multiplying both sides of this equation by <strong>n</strong> yields <strong>1.675 = 26.8 n</strong>. Dividing both sides of this equation by <strong>26.8</strong> yields <strong>n = 0.0625</strong>. Therefore, the value of <strong>n</strong> is <strong>0.0625</strong>. Note that .0625, 0.062, 0.063, and 1/16 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "c7c6445f",
type: "mcq",
questionHtml:
"A certain town has an area of <strong>4.36</strong> square miles. What is the area, in square yards, of this town? <strong>(1 mile = 1, 760 yards)</strong>",
choices: [
{ label: "A", text: "<strong>404</strong>" },
{ label: "B", text: "<strong>7, 674</strong>" },
{ label: "C", text: "<strong>710, 459</strong>" },
{ label: "D", text: "<strong>13, 505, 536</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Since the number of yards in <strong>1</strong> mile is <strong>1, 760</strong>, the number of square yards in <strong>1</strong> square mile is <strong>(1, 760) (1, 760) = 3, 097, 600</strong>. Therefore, if the area of the town is <strong>4.36</strong> square miles, it is <strong>4.36 (3, 097, 600) = 13, 505, 536</strong>, in square yards.<br>Choice A is incorrect and may result from dividing the number of yards in a mile by the square mileage of the town.<br>Choice B is incorrect and may result from multiplying the number of yards in a mile by the square mileage of the town.<br>Choice C is incorrect and may result from dividing the number of square yards in a square mile by the square mileage of the town.",
hasFigure: false,
},
{
id: "c9fb15ad",
type: "mcq",
questionHtml:
"One method of calculating the approximate age, in years, of a tree of a particular species is to multiply the diameter of the tree, in inches, by a constant called the growth factor for that species. The table above gives the growth factors for eight species of trees. If a white birch tree and a pin oak tree each now have a diameter of 1 foot, which of the following will be closest to the difference, in inches, of their diameters 10 years from now? (1 foot = 12 inches)",
choices: [
{ label: "A", text: "1.0" },
{ label: "B", text: "1.2" },
{ label: "C", text: "1.3" },
{ label: "D", text: "1.4" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. According to the given information, multiplying a tree species growth factor by the trees diameter is a method to approximate the age of the tree. A white birch with a diameter of 12 inches (or 1 foot) has a given growth factor of 5 and is approximately 60 years old. A pin oak with a diameter of 12 inches (or 1 foot) has a given growth factor of 3 and is approximately 36 years old. The diameters of the two trees 10 years from now can be found by dividing each trees age in 10 years, 70 years, and 46 years, by its respective growth factor. This yields 14 inches and <strong>15 and one third</strong> inches. The difference between <strong>15 and one third</strong> and 14 is <strong>1 and one third</strong>, or approximately 1.3 inches.Alternate approach: Since a white birch has a growth factor of 5, the age increases at a rate of 5 years per inch or, equivalently, the diameter increases at a rate of <strong>one fifth</strong> of an inch per year. Likewise, the pin oak has a growth factor of 3, so its diameter increases at a rate of <strong>one third</strong> of an inch per year. Thus, the pin oak grows <strong>two fifteenths</strong> of an inch per year more than the white birch. In 10 years it will grow <strong>two fifteenths · 10 = four thirds</strong> of an inch more, which is approximately 1.3 inches.<br>Choices A, B, and D are incorrect and a result of incorrectly calculating the diameters of the two trees in 10 years.",
hasFigure: false,
},
{
id: "d6456c7a",
type: "mcq",
questionHtml:
"A certain park has an area of <strong>11, 863, 808</strong> square yards. What is the area, in square miles, of this park? <strong>(1 mile = 1, 760 yards)</strong>",
choices: [
{ label: "A", text: "<strong>1.96</strong>" },
{ label: "B", text: "<strong>3.83</strong>" },
{ label: "C", text: "<strong>3, 444.39</strong>" },
{ label: "D", text: "<strong>6, 740.8</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Since <strong>1</strong> mile is equal to <strong>1, 760</strong> yards, <strong>1</strong> square mile is equal to <strong>1, 760²</strong>, or <strong>3, 097, 600</strong>, square yards. Its given that the park has an area of <strong>11, 863, 808</strong> square yards. Therefore, the park has an area of <strong>(11, 863, 808 square yards) ((1 square mile) / (3, 097, 600 square yards))</strong>, or <strong>(11, 863, 808) / (3, 097, 600)</strong> square miles. Thus, the area, in square miles, of the park is <strong>3.83</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect. This is the square root of the area of the park in square yards, not the area of the park in square miles.<br>Choice D is incorrect and may result from converting <strong>11, 863, 808</strong> yards to miles, rather than converting <strong>11, 863, 808</strong> square yards to square miles.",
hasFigure: false,
},
];

View File

@ -0,0 +1,466 @@
import { type PracticeQuestion } from "../../types/lesson";
export const RIGHT_TRI_TRIG_EASY: PracticeQuestion[] = [
{
id: "64c1f044",
type: "mcq",
questionHtml:
"One angle is a right angle.<br>The measure of a second angle is x°.<br>The length of the leg opposite the angle with measure x° is 26.<br>The length of the leg adjacent to the angle with measure x° is 7.<br>A note indicates the figure is not drawn to scale.<br><br>In the triangle shown, what is the value of <strong>tan x °</strong>?",
choices: [
{ label: "A", text: "<strong>one twenty sixth</strong>" },
{ label: "B", text: "<strong>(19) / (26)</strong>" },
{ label: "C", text: "<strong>(26) / (7)</strong>" },
{ label: "D", text: "<strong>(33) / (7)</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The tangent of an acute angle in a right triangle is defined as the ratio of the length of the side opposite the angle to the length of the shorter side adjacent to the angle. In the triangle shown, the length of the side opposite the angle with measure <strong>x °</strong> is <strong>26</strong> units and the length of the side adjacent to the angle with measure <strong>x °</strong> is <strong>7</strong> units. Therefore, the value of <strong>tan x °</strong> is <strong>(26) / (7)</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/64c1f044_svg1.svg",
},
{
id: "b0c5ece5",
type: "mcq",
questionHtml:
"One angle is a right angle.<br>The length of the side opposite the right angle is 19.<br>The lengths of the other 2 sides are as follows:<br><br>b<br>4<br><br>A note indicates the figure is not drawn to scale.<br><br>Which equation shows the relationship between the side lengths of the given triangle?",
choices: [
{ label: "A", text: "<strong>4 b = 19</strong>" },
{ label: "B", text: "<strong>4 + b = 19</strong>" },
{ label: "C", text: "<strong>4² + b² = 19²</strong>" },
{ label: "D", text: "<strong>4² b² = 19²</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The Pythagorean theorem states that in a right triangle, the sum of the squares of the lengths of the two legs is equal to the square of the length of the hypotenuse. Therefore, <strong>a² + b² = c²</strong>, where <strong>a</strong> and <strong>b</strong> are the lengths of the legs and <strong>c</strong> is the length of the hypotenuse. For the given right triangle, the lengths of the legs are <strong>4</strong> and <strong>b</strong>, and the length of the hypotenuse is <strong>19</strong>. Substituting <strong>4</strong> for <strong>a</strong> and <strong>19</strong> for <strong>c</strong> in the equation <strong>a² + b² = c²</strong> yields <strong>4² + b² = 19²</strong>. Thus, the relationship between the side lengths of the given triangle is <strong>4² + b² = 19²</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/b0c5ece5_svg1.svg",
},
{
id: "c9f8d1e9",
type: "mcq",
questionHtml:
"The side lengths are labeled as follows:<br><br>a<br>b<br>c<br><br>The angle opposite the side labeled c is a right angle.<br>A note indicates the figure is not drawn to scale.<br><br>For the right triangle shown, <strong>a = 4</strong> and <strong>b = 5</strong>. Which expression represents the value of <strong>c</strong>?",
choices: [
{ label: "A", text: "<strong>4 + 5</strong>" },
{ label: "B", text: "<strong>√((4) (5))</strong>" },
{ label: "C", text: "<strong>√(4 + 5)</strong>" },
{ label: "D", text: "<strong>√(4² + 5²)</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. By the Pythagorean theorem, if a right triangle has a hypotenuse with length <strong>c</strong> and legs with lengths <strong>a</strong> and <strong>b</strong>, then <strong>c² = a² + b²</strong>. In the right triangle shown, the hypotenuse has length <strong>c</strong> and the legs have lengths <strong>a</strong> and <strong>b</strong>. It's given that <strong>a = 4</strong> and <strong>b = 5</strong>. Substituting <strong>4</strong> for <strong>a</strong> and <strong>5</strong> for <strong>b</strong> in the Pythagorean theorem yields <strong>c² = 4² + 5²</strong>. Taking the square root of both sides of this equation yields <strong>c = + or √(4² + 5²)</strong>. Since the length of a side of a triangle must be positive, the value of <strong>c</strong> is <strong>√(4² + 5²)</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/c9f8d1e9_svg1.svg",
},
];
export const RIGHT_TRI_TRIG_MEDIUM: PracticeQuestion[] = [
{
id: "13d9a1c3",
type: "spr",
questionHtml:
"In the right triangle shown above, what is the length of <strong>line P Q</strong> ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 4. Triangle PQR has given angle measures of 30° and 90°, so the third angle must be 60° because the measures of the angles of a triangle sum to 180°. For any special right triangle with angles measuring 30°, 60°, and 90°, the length of the hypotenuse (the side opposite the right angle) is 2x, where x is the length of the side opposite the 30° angle. Segment PQ is opposite the 30° angle. Therefore, 2(PQ) = 8 and PQ = 4.",
hasFigure: true,
figureUrl: "/practice-images/13d9a1c3_img1.png",
},
{
id: "33e29881",
type: "mcq",
questionHtml:
"In right triangle <strong>R S T</strong>, the sum of the measures of angle <strong>R</strong> and angle <strong>S</strong> is <strong>90</strong> degrees. The value of <strong>sin (R)</strong> is <strong>(√(15)) / (4)</strong>. What is the value of <strong>cos (S)</strong>?",
choices: [
{ label: "A", text: "<strong>(√(15)) / (15)</strong>" },
{ label: "B", text: "<strong>(√(15)) / (4)</strong>" },
{ label: "C", text: "<strong>(4 √(15)) / (15)</strong>" },
{ label: "D", text: "<strong>√(15)</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The sine of any acute angle is equal to the cosine of its complement. Its given that in right triangle <strong>R S T</strong>, the sum of the measures of angle <strong>R</strong> and angle <strong>S</strong> is <strong>90</strong> degrees. Therefore, angle <strong>R</strong> and angle <strong>S</strong> are complementary, and the value of <strong>sin R</strong> is equal to the value of <strong>cos S</strong>. It's given that the value of <strong>sin R</strong> is <strong>(√(15)) / (4)</strong>, so the value of <strong>cos S</strong> is also <strong>(√(15)) / (4)</strong>.<br>Choice A is incorrect. This is the value of <strong>tan S</strong>.<br>Choice C is incorrect. This is the value of <strong>(1) / (cos S)</strong>.<br>Choice D is incorrect. This is the value of <strong>(1) / (tan S)</strong>.",
hasFigure: false,
},
{
id: "902dc959",
type: "mcq",
questionHtml:
"In the figure above, what is the value of <strong>tan A</strong>?",
choices: [
{ label: "A", text: "<strong>20 over 29</strong>" },
{ label: "B", text: "<strong>21 over 29</strong>" },
{ label: "C", text: "<strong>20 over 21</strong>" },
{ label: "D", text: "<strong>21 over 20</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Angle A is an acute angle in a right triangle, so the value of tan(A) is equivalent to the ratio of the length of the side opposite angle A, 20, to the length of the nonhypotenuse side adjacent to angle A, 21. Therefore,  <strong>tan A = 20 over 21</strong>.Choice A is incorrect. This is the value of sin(A). Choice B is incorrect. This is the value of cos(A). Choice D is incorrect. This is the value of tan(B).",
hasFigure: true,
figureUrl: "/practice-images/902dc959_img1.png",
},
{
id: "9ec76b54",
type: "mcq",
questionHtml:
"A right triangle has legs with lengths of <strong>28</strong> centimeters and <strong>20</strong> centimeters. What is the length of this triangle's hypotenuse, in centimeters?",
choices: [
{ label: "A", text: "<strong>8 √(6)</strong>" },
{ label: "B", text: "<strong>4 √(74)</strong>" },
{ label: "C", text: "<strong>48</strong>" },
{ label: "D", text: "<strong>1, 184</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The Pythagorean theorem states that in a right triangle, the sum of the squares of the lengths of the two legs is equal to the square of the length of the hypotenuse. It's given that the right triangle has legs with lengths of <strong>28</strong> centimeters and <strong>20</strong> centimeters. Let <strong>c</strong> represent the length of this triangle's hypotenuse, in centimeters. Therefore, by the Pythagorean theorem, <strong>28² + 20² = c²</strong>, or <strong>1, 184 = c²</strong>. Taking the positive square root of both sides of this equation yields <strong>√(1, 184) = c</strong>, or <strong>4 √(74) = c</strong>. Therefore, the length of this triangle's hypotenuse, in centimeters, is <strong>4 √(74)</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect. This is the square of the length of the triangles hypotenuse.",
hasFigure: false,
},
{
id: "a5aee181",
type: "mcq",
questionHtml:
"The length of a rectangles diagonal is <em>(expression)</em>, and the length of the rectangles shorter side is <em>(expression)</em>. What is the length of the rectangles longer side?",
choices: [
{ label: "A", text: "<em>(expression)</em>" },
{ label: "B", text: "<em>(expression)</em>" },
{ label: "C", text: "<em>(expression)</em>" },
{ label: "D", text: "<em>(expression)</em>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. A rectangles diagonal divides a rectangle into two congruent right triangles, where the diagonal is the hypotenuse of both triangles. Its given that the length of the diagonal is <strong>5 √(17)</strong> and the length of the rectangles shorter side is <strong>5</strong>. Therefore, each of the two right triangles formed by the rectangles diagonal has a hypotenuse with length <strong>5 √(17)</strong>, and a shorter leg with length <strong>5</strong>. To calculate the length of the longer leg of each right triangle, the Pythagorean theorem, <strong>a² + b² = c²</strong>, can be used, where <strong>a</strong> and <strong>b</strong> are the lengths of the legs and <strong>c</strong> is the length of the hypotenuse of the triangle. Substituting <strong>5</strong> for <strong>a</strong> and <strong>5 √(17)</strong> for <strong>c</strong> in the equation <strong>a² + b² = c²</strong>  yields <strong>5² + b² = (5 √(17))²</strong>, which is equivalent to <strong>25 + b² = 25 (17)</strong>, or <strong>25 + b² = 425</strong>. Subtracting <strong>25</strong> from each side of this equation yields <strong>b² = 400</strong>. Taking the positive square root of each side of this equation yields <strong>b = 20</strong>. Therefore, the length of the longer leg of each right triangle formed by the diagonal of the rectangle is <strong>20</strong>. It follows that the length of the rectangles longer side is <strong>20</strong>.<br>Choice A is incorrect and may result from dividing the length of the rectangles diagonal by the length of the rectangles shorter side, rather than substituting these values into the Pythagorean theorem.<br>Choice C is incorrect and may result from using the length of the rectangles diagonal as the length of a leg of the right triangle, rather than the length of the hypotenuse.<br>Choice D is incorrect. This is the square of the length of the rectangles longer side.",
hasFigure: false,
},
{
id: "bcb66188",
type: "mcq",
questionHtml:
"Triangle <strong>F G H</strong> is similar to triangle <strong>J K L</strong>, where angle <strong>F</strong> corresponds to angle <strong>J</strong> and angles <strong>G</strong> and <strong>K</strong> are right angles. If <strong>sin (F) = (308) / (317)</strong>, what is the value of <strong>sin (J)</strong>?",
choices: [
{ label: "A", text: "<strong>(75) / (317)</strong>" },
{ label: "B", text: "<strong>(308) / (317)</strong>" },
{ label: "C", text: "<strong>(317) / (308)</strong>" },
{ label: "D", text: "<strong>(317) / (75)</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. If two triangles are similar, then their corresponding angles are congruent. It's given that right triangle <strong>F G H</strong> is similar to right triangle <strong>J K L</strong> and angle <strong>F</strong> corresponds to angle <strong>J</strong>. It follows that angle <strong>F</strong> is congruent to angle <strong>J</strong> and, therefore, the measure of angle <strong>F</strong> is equal to the measure of angle <strong>J</strong>. The sine ratios of angles of equal measure are equal. Since the measure of angle <strong>F</strong> is equal to the measure of angle <strong>J</strong>, <strong>sin (F) = sin (J)</strong>. It's given that <strong>sin (F) = (308) / (317)</strong>. Therefore,  <strong>sin (J)</strong> is <strong>(308) / (317)</strong>.<br>Choice A is incorrect. This is the value of <strong>cos (J)</strong>, not the value of <strong>sin (J)</strong>.<br>Choice C is incorrect. This is the reciprocal of the value of <strong>sin (J)</strong>, not the value of <strong>sin (J)</strong>.<br>Choice D is incorrect. This is the reciprocal of the value of <strong>cos (J)</strong>, not the value of <strong>sin (J)</strong>.",
hasFigure: false,
},
{
id: "bf8d843e",
type: "mcq",
questionHtml:
"In <strong>triangle A, B C</strong> above, what is the length of  <strong>A, D</strong>?",
choices: [
{ label: "A", text: "4" },
{ label: "B", text: "6" },
{ label: "C", text: "<strong>6 · the √ 2</strong>" },
{ label: "D", text: "<strong>6 · the √ 3</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Triangles ADB and CDB are both <strong>30 ° 60 ° 90 °</strong> triangles and share <strong>side B D</strong> . Therefore, triangles ADB and CDB are congruent by the angle-side-angle postulate. Using the properties of <strong>30 ° 60 ° 90 °</strong> triangles, the length of <strong>side A, D</strong> is half the length of hypotenuse <strong>A, B</strong> . Since the triangles are congruent, <strong>the length of side A, B = the length of side B C, which = 12</strong>. So the length of <strong>side A, D</strong> is <strong>twelve halves = 6</strong>.Alternate approach: Since angle CBD has a measure of <strong>30 °</strong>, angle ABC must have a measure of <strong>60 °</strong>. It follows that triangle ABC is equilateral, so side AC also has length 12. It also follows that the altitude BD is also a median, and therefore the length of AD is half of the length of AC, which is 6.<br>Choice A is incorrect. If the length of <strong>side A, D</strong> were 4, then the length of <strong>side A, B</strong> would be 8. However, this is incorrect because <strong>side A, B</strong> is congruent to <strong>side B C</strong>, which has a length of 12. Choices C and D are also incorrect. Following the same procedures as used to test choice A gives <strong>side A, B</strong> a length of <strong>12 · the √ 2</strong> for choice C and <strong>12 · the √ 3</strong> for choice D. However, these results cannot be true because <strong>side A, B</strong> is congruent to <strong>side B C</strong>, which has a length of 12.",
hasFigure: true,
figureUrl: "/practice-images/bf8d843e_img1.png",
},
{
id: "de550be0",
type: "mcq",
questionHtml:
"One angle is a right angle.<br>The length of the side opposite the right angle is 21.<br>The length of one side adjacent to the right angle is 6.<br>The length of the other side adjacent to the right angle is a.<br>A note indicates the figure is not drawn to scale.<br><br>For the triangle shown, which expression represents the value of <strong>a</strong>?",
choices: [
{ label: "A", text: "<strong>√(21² 6²)</strong>" },
{ label: "B", text: "<strong>21² 6²</strong>" },
{ label: "C", text: "<strong>√(21 6)</strong>" },
{ label: "D", text: "<strong>21 6</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. For the right triangle shown, the lengths of the legs are <strong>a</strong> units and <strong>6</strong> units, and the length of the hypotenuse is <strong>21</strong> units. The Pythagorean theorem states that in a right triangle, the sum of the squares of the lengths of the two legs is equal to the square of the length of the hypotenuse. Therefore, <strong>a² + 6² = 21²</strong>. Subtracting <strong>6²</strong> from both sides of this equation yields <strong>a² = 21² 6²</strong>. Taking the square root of both sides of this equation yields <strong>a = + or √(21² 6²)</strong>. Since <strong>a</strong> is a length, <strong>a</strong> must be positive. Therefore, <strong>a = √(21² 6²)</strong>. Thus, for the triangle shown, <strong>√(21² 6²)</strong> represents the value of <strong>a</strong>.<br>Choice B is incorrect. For the triangle shown, this expression represents the value of <strong>a²</strong>, not <strong>a</strong>.<br>Choice C is incorrect and may result from conceptual errors.<br>Choice D is incorrect and may result from conceptual errors.",
hasFigure: true,
figureUrl: "/practice-images/de550be0_svg1.svg",
},
];
export const RIGHT_TRI_TRIG_HARD: PracticeQuestion[] = [
{
id: "0e709a29",
type: "mcq",
questionHtml:
"<strong>R S = 440</strong><br><strong>S T = 384</strong><br><strong>T R = 584</strong><br>The side lengths of right triangle <strong>R S T</strong> are given. Triangle <strong>R S T</strong>  is similar to triangle <strong>U V W</strong>, where <strong>S</strong> corresponds to <strong>V</strong> and <strong>T</strong> corresponds to <strong>W</strong>. What is the value of <strong>tan W</strong>?",
choices: [
{ label: "A", text: "<strong>(48) / (73)</strong>" },
{ label: "B", text: "<strong>(55) / (73)</strong>" },
{ label: "C", text: "<strong>(48) / (55)</strong>" },
{ label: "D", text: "<strong>(55) / (48)</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The hypotenuse of triangle <strong>R S T</strong> is the longest side and is across from the right angle. The longest side length given is <strong>584</strong>, which is the length of side <strong>T R</strong>. Therefore, the hypotenuse of triangle <strong>R S T</strong> is side <strong>T R</strong>, so the right angle is angle <strong>S</strong>. The tangent of an acute angle in a right triangle is the ratio of the length of the opposite side, which is the side across from the angle, to the length of the adjacent side, which is the side closest to the angle that is not the hypotenuse. It follows that the opposite side of angle <strong>T</strong> is side <strong>R S</strong> and the adjacent side of angle <strong>T</strong> is side <strong>S T</strong>. Therefore, <strong>tan T = (R S) / (S T)</strong>. Substituting <strong>440</strong> for <strong>R S</strong> and <strong>384</strong> for <strong>S T</strong> in this equation yields <strong>tan T = (440) / (384)</strong>. This is equivalent to <strong>tan T = (55) / (48)</strong>. Its given that triangle <strong>R S T</strong> is similar to triangle <strong>U V W</strong>, where <strong>S</strong> corresponds to <strong>V</strong> and <strong>T</strong> corresponds to <strong>W</strong>. It follows that <strong>R</strong> corresponds to <strong>U</strong>. Therefore, the hypotenuse of triangle <strong>U V W</strong> is side <strong>W U</strong>, which means <strong>tan W = (U V) / (V W)</strong>. Since the lengths of corresponding sides of similar triangles are proportional, <strong>(R S) / (S T) = (U V) / (V W)</strong>. Therefore, <strong>tan W = (U V) / (V W)</strong> is equivalent to <strong>tan W = (R S) / (S T)</strong>, or <strong>tan W = tan T</strong>. Thus, <strong>tan W = (55) / (48)</strong>.<br>Choice A is incorrect. This is the value of <strong>cos W</strong>, not <strong>tan W</strong>.<br>Choice B is incorrect. This is the value of <strong>sin W</strong>, not <strong>tan W</strong>.<br>Choice C is incorrect. This is the value of <strong>(1) / (tan W)</strong>, not <strong>tan W</strong>.",
hasFigure: false,
},
{
id: "1429dcdf",
type: "spr",
questionHtml:
"One angle is a right angle.<br>The measure of a second angle is x°.<br>The length of the hypotenuse is 23.<br>The length of the leg opposite the angle with measure x° is 16.<br>A note indicates the figure is not drawn to scale.<br><br>In the triangle shown, what is the value of <strong>sin x °</strong>?",
choices: [],
correctAnswer: ".6956, .6957, 16/23",
explanation:
"The correct answer is <strong>(16) / (23)</strong>. In a right triangle, the sine of an acute angle is defined as the ratio of the length of the side opposite the angle to the length of the hypotenuse. In the triangle shown, the length of the side opposite the angle with measure <strong>x °</strong> is <strong>16</strong> units and the length of the hypotenuse is <strong>23</strong> units. Therefore, the value of <strong>sin x °</strong> is <strong>(16) / (23)</strong>. Note that 16/23, .6956, .6957, 0.695, and 0.696 are examples of ways to enter a correct answer.",
hasFigure: true,
figureUrl: "/practice-images/1429dcdf_svg1.svg",
},
{
id: "25da87f8",
type: "spr",
questionHtml:
"A triangle with angle measures 30°, 60°, and 90° has a perimeter of <strong>18 + 6 · the √ 3</strong>. What is the length of the longest side of the triangle?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 12. It is given that the triangle has angle measures of 30°, 60°, and 90°, and so the triangle is a special right triangle. The side measures of this type of special triangle are in the ratio <strong>2 to 1 to the √ 3</strong>. If x is the measure of the shortest leg, then the measure of the other leg is <strong>the √ 3 end root x</strong> and the measure of the hypotenuse is 2x. The perimeter of the triangle is given to be <strong>18 + 6 · the √ 3, end root</strong>, and so the equation for the perimeter can be written as <strong>2 x + x + the √ 3 end root x = 18 + 6 · the √ 3</strong>. Combining like terms and factoring out a common factor of x on the left-hand side of the equation gives <strong>(3 + the √ 3, ) · x = 18 + 6 · the √ 3</strong>. Rewriting the right-hand side of the equation by factoring out 6 gives <strong>(3 + the √ 3, ) · x = 6 · (3 + the √ 3, )</strong>. Dividing both sides of the equation by the common factor <strong>(3 + the √ 3, )</strong> gives x = 6. The longest side of the right triangle, the hypotenuse, has a length of 2x, or 2(6), which is 12.",
hasFigure: false,
},
{
id: "2be01bd9",
type: "spr",
questionHtml:
"Triangle <strong>A B C</strong> is similar to triangle <strong>D E F</strong>, where angle <strong>A</strong> corresponds to angle <strong>D</strong> and angle <strong>C</strong> corresponds to angle <strong>F</strong>.  Angles <strong>C</strong> and <strong>F</strong> are right angles. If <strong>tan (A) = (50) / (7)</strong>, what is the value of  <strong>tan (E)</strong>?",
choices: [],
correctAnswer: ".14, 7/50",
explanation:
"The correct answer is <strong>seven fiftieths</strong>. It's given that triangle <strong>A B C</strong> is similar to triangle <strong>D E F</strong>, where angle <strong>A</strong> corresponds to angle <strong>D</strong> and angle <strong>C</strong> corresponds to angle <strong>F</strong>. In similar triangles, the tangents of corresponding angles are equal. Since angle <strong>A</strong> and angle <strong>D</strong> are corresponding angles, if <strong>tan (A) = (50) / (7)</strong>, then <strong>tan (D) = (50) / (7)</strong>. It's also given that angles <strong>C</strong> and <strong>F</strong> are right angles. It follows that triangle <strong>D E F</strong> is a right triangle with acute angles <strong>D</strong> and <strong>E</strong>. The tangent of one acute angle in a right triangle is the inverse of the tangent of the other acute angle in the triangle. Therefore, <strong>tan (E) = (1) / (tan (D))</strong>. Substituting <strong>(50) / (7)</strong> for <strong>tan (D)</strong> in this equation yields <strong>tan (E) = Start(1 OverOver StartFraction 50) / (7) EndEndFraction</strong>, or <strong>tan (E) = seven fiftieths</strong>. Thus, if <strong>tan (A) = (50) / (7)</strong>, the value of <strong>tan (E)</strong> is <strong>seven fiftieths</strong>. Note that 7/50 and .14 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "4c95c7d4",
type: "mcq",
questionHtml:
"A graphic designer is creating a logo for a company. The logo is shown in the figure above. The logo is in the shape of a trapezoid and consists of three congruent equilateral triangles. If the perimeter of the logo is 20 centimeters, what is the combined area of the shaded regions, in square centimeters, of the logo?",
choices: [
{ label: "A", text: "<strong>2 · the √ 3</strong>" },
{ label: "B", text: "<strong>4 · the √ 3</strong>" },
{ label: "C", text: "<strong>8 · the √ 3</strong>" },
{ label: "D", text: "<strong>16</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that the logo is in the shape of a trapezoid that consists of three congruent equilateral triangles, and that the perimeter of the trapezoid is 20 centimeters (cm). Since the perimeter of the trapezoid is the sum of the lengths of 5 of the sides of the triangles, the length of each side of an equilateral triangle is <strong>the fraction 20 over 5 = 4 centimeters</strong>. Dividing up one equilateral triangle into two right triangles yields a pair of congruent 30°-60°-90° triangles. The shorter leg of each right triangle is half the length of the side of an equilateral triangle, or 2 cm. Using the Pythagorean Theorem, <strong>a, ² + b² = c²</strong>, the height of the equilateral triangle can be found. Substituting <strong>a = 2</strong> and <strong>c = 4</strong> and solving for b yields <strong>the √, 4² 2², end root = the √ 12, which = 2 · the √ 3 centimeters</strong> cm. The area of one equilateral triangle is <strong>one half b h</strong>, where <strong>b = 2</strong> and <strong>h = 2 · the √ 3</strong>. Therefore, the area of one equilateral triangle is <strong>one half · 4 · (2 · the √ 3, ) = 4 · the √ 3 centimeters²</strong>. The shaded area consists of two such triangles, so its area is <strong>2 · 4 · the √ 3 = 8 · the √ 3 centimeters²</strong>.Alternate approach: The area of a trapezoid can be found by evaluating the expression <strong>one half · (b sub 1 + b sub 2, ) · h</strong>, where <strong>b sub 1</strong>is the length of one base, <strong>b sub 2</strong> is the length of the other base, and h is the height of the trapezoid. Substituting <strong>b sub 1 = 8</strong>, <strong>b sub 2 = 4</strong>, and <strong>h = 2 · the √ 3</strong> yields the expression <strong>one half · (8 + 4, ) · (2 · the √ 3, )</strong>, or <strong>one half · 12 · (2 · the √ 3, )</strong>, which gives an area of <strong>12 · the √ 3 centimeters²</strong> for the trapezoid. Since two-thirds of the trapezoid is shaded, the area of the shaded region is <strong>two thirds · 12 · the √ 3 = 8 · the √ 3</strong>.<br>Choice A is incorrect. This is the height of the trapezoid. Choice B is incorrect. This is the area of one of the equilateral triangles, not two. Choice D is incorrect and may result from using a height of 4 for each triangle rather than the height of <strong>2 · the √ 3</strong>.",
hasFigure: true,
figureUrl: "/practice-images/4c95c7d4_img1.png",
},
{
id: "55bb437a",
type: "spr",
questionHtml:
"In the figure above, <strong>tan of B = the fraction 3 over 4</strong>. If <strong>B C = 15</strong> and <strong>D A = 4</strong>, what is the length of <strong>D E</strong> ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 6. Since <strong>tan of B = three fourths</strong>, <strong>triangle A, B C</strong> and <strong>triangle D B E</strong> are both similar to 3-4-5 triangles. This means that they are both similar to the right triangle with sides of lengths 3, 4, and 5. Since <strong>the length of side B C = 15</strong>, which is 3 times as long as the hypotenuse of the 3-4-5 triangle, the similarity ratio of <strong>triangle A, B C</strong> to the 3-4-5 triangle is 3:1. Therefore, the length of <strong>side A, C</strong> (the side opposite to <strong>angle B</strong>) is <strong>3 · 3 = 9</strong>, and the length of <strong>side A, B</strong> (the side adjacent to <strong>angle B</strong>) is <strong>4 · 3 = 12</strong>. It is also given that <strong>the length of side D A = 4</strong>. Since <strong>the length of side A, B = the length of side D A + the length of side D B</strong> and <strong>the length of side A, B = 12</strong>, it follows that <strong>the length of side D B = 8</strong>, which means that the similarity ratio of <strong>triangle D B E</strong> to the 3-4-5 triangle is 2:1 ( <strong>side D B</strong> is the side adjacent to <strong>angle B</strong>). Therefore, the length of <strong>side D E</strong>, which is the side opposite to <strong>angle B</strong>, is <strong>3 · 2 = 6</strong>.",
hasFigure: true,
figureUrl: "/practice-images/55bb437a_img1.png",
},
{
id: "568d66a7",
type: "mcq",
questionHtml:
"An isosceles right triangle has a perimeter of <strong>94 + 94 √(2)</strong> inches. What is the length, in inches, of one leg of this triangle?",
choices: [
{ label: "A", text: "<strong>47</strong>" },
{ label: "B", text: "<strong>47 √(2)</strong>" },
{ label: "C", text: "<strong>94</strong>" },
{ label: "D", text: "<strong>94 √(2)</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. It's given that the right triangle is isosceles. In an isosceles right triangle, the two legs have equal lengths, and the length of the hypotenuse is <strong>√(2)</strong> times the length of one of the legs. Let <strong>script l</strong> represent the length, in inches, of each leg of the isosceles right triangle. It follows that the length of the hypotenuse is <strong>script l √(2)</strong> inches. The perimeter of a figure is the sum of the lengths of the sides of the figure. Therefore, the perimeter of the isosceles right triangle is <strong>script l + script l + script l √(2)</strong> inches. It's given that the perimeter of the triangle is <strong>94 + 94 √(2)</strong> inches. It follows that <strong>script l + script l + script l √(2) = 94 + 94 √(2)</strong>. Factoring the left-hand side of this equation yields <strong>(1 + 1 + √(2)) script l = 94 + 94 √(2)</strong>, or <strong>(2 + √(2)) script l = 94 + 94 √(2)</strong>. Dividing both sides of this equation by <strong>2 + √(2)</strong> yields <strong>script l = (94 + 94 √(2)) / (2 + √(2))</strong>. Rationalizing the denominator of the right-hand side of this equation by multiplying the right-hand side of the equation by <strong>(2 √(2)) / (2 √(2))</strong> yields <strong>script l = ((94 + 94 √(2)) (2 √(2))) / ((2 + √(2)) (2 √(2)))</strong>. Applying the distributive property to the numerator and to the denominator of the right-hand side of this equation yields <strong>script l = (188 94 √(2) + 188 √(2) 94 √(4)) / (4 2 √(2) + 2 √(2) √(4))</strong>. This is equivalent to <strong>script l = (94 √(2)) / (2)</strong>, or <strong>script l = 47 √(2)</strong>. Therefore, the length, in inches, of one leg of the isosceles right triangle is <strong>47 √(2)</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect. This is the length, in inches, of the hypotenuse.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "6933b3d9",
type: "spr",
questionHtml:
"<strong>The figure presents right triangle R S T such that side R T is horizontal, vertex T is to the right of vertex R, and vertex S is above R T. Side R S is labeled 12. Side S T is labeled 5. Angle S is a right angle</strong>In triangle RST above, point W (not shown) lies on <strong>R T</strong>. What is the value of <strong>cos of angle R S W sin of angle W S T</strong> ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 0. Note that no matter where point W is on <strong>side R T</strong>, the sum of the measures of <strong>angle R S W</strong> and <strong>angle W S T</strong> is equal to the measure of <strong>angle R S T</strong>, which is <strong>90 °</strong>. Thus, <strong>angle R S W</strong> and <strong>angle W S T</strong> are complementary angles. Since the cosine of an angle is equal to the sine of its complementary angle, <strong>the cos of angle R S W = the sin of angle W S T</strong>. Therefore, <strong>the cos of angle R S W the sin of angle W S T = 0</strong>.",
hasFigure: true,
figureUrl: "/practice-images/6933b3d9_img1.png",
},
{
id: "6ab30ce3",
type: "mcq",
questionHtml:
"Triangle <strong>A B C</strong> is similar to triangle <strong>D E F</strong>, where <strong>A</strong> corresponds to <strong>D</strong> and <strong>C</strong> corresponds to <strong>F</strong>. Angles <strong>C</strong> and <strong>F</strong> are right angles. If <strong>tan (A) = √(3)</strong> and <strong>D F = 125</strong>, what is the length of <strong>D E</strong>?",
choices: [
{ label: "A", text: "<strong>125 (√(3)) / (3)</strong>" },
{ label: "B", text: "<strong>125 (√(3)) / (2)</strong>" },
{ label: "C", text: "<strong>125 √(3)</strong>" },
{ label: "D", text: "<strong>250</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Corresponding angles in similar triangles have equal measures. It's given that triangle <strong>A B C</strong> is similar to triangle <strong>D E F</strong>, where <strong>A</strong> corresponds to <strong>D</strong>, so the measure of angle <strong>A</strong> is equal to the measure of angle <strong>D</strong>. Therefore, if <strong>tan (A) = √(3)</strong>, then <strong>tan (D) = √(3)</strong>. It's given that angles <strong>C</strong> and <strong>F</strong> are right angles, so triangles <strong>A B C</strong> and <strong>D E F</strong> are right triangles. The adjacent side of an acute angle in a right triangle is the side closest to the angle that is not the hypotenuse. It follows that the adjacent side of angle <strong>D</strong> is side <strong>D F</strong>. The opposite side of an acute angle in a right triangle is the side across from the acute angle. It follows that the opposite side of angle <strong>D</strong> is side <strong>E F</strong>. The tangent of an acute angle in a right triangle is the ratio of the length of the opposite side to the length of the adjacent side. Therefore, <strong>tan (D) = (E F) / (D F)</strong>. If <strong>D F = 125</strong>, the length of side <strong>E F</strong> can be found by substituting <strong>√(3)</strong> for <strong>tan (D)</strong> and <strong>125</strong> for <strong>D F</strong> in the equation <strong>tan (D) = (E F) / (D F)</strong>, which yields <strong>√(3) = (E F) / (125)</strong>. Multiplying both sides of this equation by <strong>125</strong> yields <strong>125 √(3) = E F</strong>. Since the length of side <strong>E F</strong> is <strong>√(3)</strong> times the length of side <strong>D F</strong>, it follows that triangle <strong>D E F</strong> is a special right triangle with angle measures <strong>30 °</strong>, <strong>60 °</strong>, and <strong>90 °</strong>. Therefore, the length of the hypotenuse, <strong>D E</strong>, is <strong>2</strong> times the length of side <strong>D F</strong>, or <strong>D E = 2 (D F)</strong>. Substituting <strong>125</strong> for <strong>D F</strong> in this equation yields <strong>D E = 2 (125)</strong>, or <strong>D E = 250</strong>. Thus, if <strong>tan (A) = √(3)</strong> and <strong>D F = 125</strong>, the length of <strong>D E</strong> is <strong>250</strong>.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice B is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect. This is the length of <strong>E F</strong>, not <strong>D E</strong>.",
hasFigure: false,
},
{
id: "7c25b0dc",
type: "spr",
questionHtml:
"The length of a rectangles diagonal is <strong>3 √(17)</strong>, and the length of the rectangles shorter side is <strong>3</strong>. What is the length of the rectangles longer side?",
choices: [],
correctAnswer: "12",
explanation:
"The correct answer is <strong>12</strong>. The diagonal of a rectangle forms a right triangle, where the shorter side and the longer side of the rectangle are the legs of the triangle and the diagonal of the rectangle is the hypotenuse of the triangle. It's given that the length of the rectangle's diagonal is <strong>3 √(17)</strong> and the length of the rectangle's shorter side is <strong>3</strong>. Thus, the length of the hypotenuse of the right triangle formed by the diagonal is <strong>3 √(17)</strong> and the length of one of the legs is <strong>3</strong>. By the Pythagorean theorem, if a right triangle has a hypotenuse with length <strong>c</strong> and legs with lengths <strong>a</strong> and <strong>b</strong>, then <strong>a² + b² = c²</strong>. Substituting <strong>3 √(17)</strong> for <strong>c</strong> and <strong>3</strong> for <strong>b</strong> in this equation yields <strong>a² + (3)² = (3 √(17))²</strong>, or <strong>a² + 9 = 153</strong>. Subtracting <strong>9</strong> from both sides of this equation yields <strong>a² = 144</strong>. Taking the square root of both sides of this equation yields <strong>a = + or √(144)</strong>, or <strong>a = + or 12</strong>. Since <strong>a</strong> represents a length, which must be positive, the value of <strong>a</strong> is <strong>12</strong>. Thus, the length of the rectangle's longer side is <strong>12</strong>.",
hasFigure: false,
},
{
id: "8027db3f",
type: "spr",
questionHtml:
"In triangle <strong>J K L</strong>, <strong>cos (K) = (24) / (51)</strong> and angle <strong>J</strong> is a right angle. What is the value of <strong>cos (L)</strong>?",
choices: [],
correctAnswer: ".8823, .8824, 15/17",
explanation:
"The correct answer is <strong>(15) / (17)</strong>. It's given that angle <strong>J</strong> is the right angle in triangle <strong>J K L</strong>. Therefore, the acute angles of triangle <strong>J K L</strong> are angle <strong>K</strong> and angle <strong>L</strong>. The hypotenuse of a right triangle is the side opposite its right angle. Therefore, the hypotenuse of triangle <strong>J K L</strong> is side <strong>K L</strong>. The cosine of an acute angle in a right triangle is the ratio of the length of the side adjacent to the angle to the length of the hypotenuse. It's given that <strong>cos (K) = (24) / (51)</strong>. This can be written as <strong>cos (K) = eight seventeenths</strong>. Since the cosine of angle <strong>K</strong> is a ratio, it follows that the length of the side adjacent to angle <strong>K</strong> is <strong>8 n</strong> and the length of the hypotenuse is <strong>17 n</strong>, where <strong>n</strong> is a constant. Therefore, <strong>J K = 8 n</strong> and <strong>K L = 17 n</strong>. The Pythagorean theorem states that in a right triangle, the square of the length of the hypotenuse is equal to the sum of the squares of the lengths of the other two sides. For triangle <strong>J K L</strong>, it follows that <strong>(J K)² + (J L)² = (K L)²</strong>. Substituting <strong>8 n</strong> for <strong>J K</strong> and <strong>17 n</strong> for <strong>K L</strong> yields <strong>(8 n)² + (J L)² = (17 n)²</strong>. This is equivalent to <strong>64 n² + (J L)² = 289 n²</strong>. Subtracting <strong>64 n²</strong> from each side of this equation yields <strong>(J L)² = 225 n²</strong>. Taking the square root of each side of this equation yields <strong>J L = 15 n</strong>. Since <strong>cos (L) = (J L) / (K L)</strong>, it follows that <strong>cos (L) = (15 n) / (17 n)</strong>, which can be rewritten as <strong>cos (L) = (15) / (17)</strong>. Note that 15/17, .8824, .8823, and 0.882 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "92eb236a",
type: "mcq",
questionHtml:
"In a right triangle, the tangent of one of the two acute angles is <strong>the fraction with numerator the √ 3, and denominator 3</strong>. What is the tangent of the other acute angle?",
choices: [
{
label: "A",
text: "<strong>the of the fraction with numerator the √ 3, and denominator 3</strong>",
},
{
label: "B",
text: "<strong>the of the fraction with numerator 3, and denominator the √ 3</strong>",
},
{
label: "C",
text: "<strong>the fraction with numerator the √ 3, and denominator 3</strong>",
},
{
label: "D",
text: "<strong>the fraction with numerator 3, and denominator the √ 3</strong>",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. The tangent of a nonright angle in a right triangle is defined as the ratio of the length of the leg opposite the angle to the length of the leg adjacent to the angle. Using that definition for tangent, in a right triangle with legs that have lengths a and b, the tangent of one acute angle is <strong>the fraction a, over b</strong> and the tangent for the other acute angle is <strong>the fraction b over a</strong>. It follows that the tangents of the acute angles in a right triangle are reciprocals of each other. Therefore, the tangent of the other acute angle in the given triangle is the reciprocal of <strong>the fraction, the √ 3, end root, over 3, end fraction</strong> or <strong>the fraction, 3 over the √ 3, end fraction</strong>.Choice A is incorrect and may result from assuming that the tangent of the other acute angle is the negative of the tangent of the angle described. Choice B is incorrect and may result from assuming that the tangent of the other acute angle is the negative of the reciprocal of the tangent of the angle described. Choice C is incorrect and may result from interpreting the tangent of the other acute angle as equal to the tangent of the angle described.",
hasFigure: false,
},
{
id: "a4bd60a3",
type: "spr",
questionHtml:
"The perimeter of an equilateral triangle is <strong>624</strong> centimeters. The height of this triangle is <strong>k √(3)</strong> centimeters, where <strong>k</strong> is a constant. What is the value of <strong>k</strong>?",
choices: [],
correctAnswer: "104",
explanation:
"The correct answer is <strong>104</strong>. An equilateral triangle is a triangle in which all three sides have the same length and all three angles have a measure of <strong>60 °</strong>. The height of the triangle, <strong>k √(3)</strong>, is the length of the altitude from one vertex. The altitude divides the equilateral triangle into two congruent 30-60-90 right triangles, where the altitude is the side across from the <strong>60 °</strong> angle in each 30-60-90 right triangle. Since the altitude has a length of <strong>k √(3)</strong>, it follows from the properties of 30-60-90 right triangles that the side across from each <strong>30 °</strong> angle has a length of <strong>k</strong> and each hypotenuse has a length of <strong>2 k</strong>. In this case, the hypotenuse of each 30-60-90 right triangle is a side of the equilateral triangle; therefore, each side length of the equilateral triangle is <strong>2 k</strong>. The perimeter of a triangle is the sum of the lengths of each side. It's given that the perimeter of the equilateral triangle is <strong>624</strong>; therefore, <strong>2 k + 2 k + 2 k = 624</strong>, or <strong>6 k = 624</strong>. Dividing both sides of this equation by <strong>6</strong> yields <strong>k = 104</strong>.",
hasFigure: false,
},
{
id: "ae041e52",
type: "mcq",
questionHtml:
"A square is inscribed in a circle. The radius of the circle is <strong>(20 √(2)) / (2)</strong> inches. What is the side length, in inches, of the square?",
choices: [
{ label: "A", text: "<strong>20</strong>" },
{ label: "B", text: "<strong>(20 √(2)) / (2)</strong>" },
{ label: "C", text: "<strong>20 √(2)</strong>" },
{ label: "D", text: "<strong>40</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. When a square is inscribed in a circle, a diagonal of the square is a diameter of the circle. It's given that a square is inscribed in a circle and the length of a radius of the circle is <strong>(20 √(2)) / (2)</strong> inches. Therefore, the length of a diameter of the circle is <strong>2 ((20 √(2)) / (2))</strong> inches, or <strong>20 √(2)</strong> inches. It follows that the length of a diagonal of the square is <strong>20 √(2)</strong> inches. A diagonal of a square separates the square into two right triangles in which the legs are the sides of the square and the hypotenuse is a diagonal. Since a square has <strong>4</strong> congruent sides, each of these two right triangles has congruent legs and a hypotenuse of length <strong>20 √(2)</strong> inches. Since each of these two right triangles has congruent legs, they are both <strong>45</strong>-<strong>45</strong>-<strong>90</strong> triangles. In a <strong>45</strong>-<strong>45</strong>-<strong>90</strong> triangle, the length of the hypotenuse is <strong>√(2)</strong> times the length of a leg. Let <strong>s</strong> represent the length of a leg of one of these <strong>45</strong>-<strong>45</strong>-<strong>90</strong> triangles. It follows that <strong>20 √(2) = √(2) (s)</strong>. Dividing both sides of this equation by <strong>√(2)</strong> yields <strong>20 = s</strong>. Therefore, the length of a leg of one of these <strong>45</strong>-<strong>45</strong>-<strong>90</strong> triangles is <strong>20</strong> inches. Since the legs of these two <strong>45</strong>-<strong>45</strong>-<strong>90</strong> triangles are the sides of the square, it follows that the side length of the square is <strong>20</strong> inches.<br>Choice B is incorrect. This is the length of a radius, in inches, of the circle.<br>Choice C is incorrect. This is the length of a diameter, in inches, of the circle.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "bd87bc09",
type: "spr",
questionHtml:
"Triangle <strong>A, B C</strong> above is a right triangle, and <strong>the sin of B = 5 over 13</strong>. What is the length of side <strong>B C</strong>?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 24. The sine of an acute angle in a right triangle is equal to the ratio of the length of the side opposite the angle to the length of the hypotenuse. In the triangle shown, the sine of angle B, or <strong>sin of B</strong>, is equal to the ratio of the length of side <strong>A, C</strong> to the length of side <strong>A, B</strong>. Its given that the length of side <strong>A, B</strong> is 26 and that <strong>sin of B = 5 over 13</strong>. Therefore, <strong>the fraction 5 over 13 = the fraction A, B over 26</strong>. Multiplying both sides of this equation by 26 yields <strong>A, C = 10</strong>.By the Pythagorean Theorem, the relationship between the lengths of the sides of triangle ABC is as follows: <strong>26² = 10² + B C²</strong>, or <strong>676 = 100 + B C²</strong>. Subtracting 100 from both sides of <strong>676 = 100 + B C²</strong> yields <strong>576 = B C²</strong>. Taking the square root of both sides of <strong>576 = B C²</strong> yields <strong>24 = B C</strong>.",
hasFigure: true,
figureUrl: "/practice-images/bd87bc09_img1.png",
},
{
id: "c6dff223",
type: "spr",
questionHtml:
"Triangle <strong>A B C</strong> is similar to triangle <strong>D E F</strong>, where angle <strong>A</strong> corresponds to angle <strong>D</strong> and angles <strong>C</strong> and <strong>F</strong> are right angles. The length of <strong>A B</strong> is <strong>2.9</strong> times the length of <strong>D E</strong>. If <strong>tan A = (21) / (20)</strong>, what is the value of <strong>sin D</strong>?",
choices: [],
correctAnswer: ".7241, 21/29",
explanation:
"The correct answer is <strong>(21) / (29)</strong>. It's given that triangle <strong>A B C</strong> is similar to triangle <strong>D E F</strong>, where angle <strong>A</strong> corresponds to angle <strong>D</strong> and angles <strong>C</strong> and <strong>F</strong> are right angles. In similar triangles, the tangents of corresponding angles are equal. Therefore, if <strong>tan A = (21) / (20)</strong>, then <strong>tan D = (21) / (20)</strong>. In a right triangle, the tangent of an acute angle is the ratio of the length of the leg opposite the angle to the length of the leg adjacent to the angle. Therefore, in triangle <strong>D E F</strong>, if <strong>tan D = (21) / (20)</strong>, the ratio of the length of <strong>E F</strong> to the length of <strong>D F</strong> is <strong>(21) / (20)</strong>. If the lengths of <strong>E F</strong> and <strong>D F</strong> are <strong>21</strong> and <strong>20</strong>, respectively, then the ratio of the length of <strong>E F</strong> to the length of <strong>D F</strong> is <strong>(21) / (20)</strong>. In a right triangle, the sine of an acute angle is the ratio of the length of the leg opposite the angle to the length of the hypotenuse. Therefore, the value of <strong>sin D</strong> is the ratio of the length of <strong>E F</strong> to the length of <strong>D E</strong>. The length of <strong>D E</strong> can be calculated using the Pythagorean theorem, which states that if the lengths of the legs of a right triangle are <strong>a</strong> and <strong>b</strong> and the length of the hypotenuse is <strong>c</strong>, then <strong>a² + b² = c²</strong>. Therefore, if the lengths of <strong>E F</strong> and <strong>D F</strong> are <strong>21</strong> and <strong>20</strong>, respectively, then <strong>(21)² + (20)² = (D E)²</strong>, or <strong>841 = (D E)²</strong>. Taking the positive square root of both sides of this equation yields <strong>29 = D E</strong>. Therefore, if the lengths of <strong>E F</strong> and <strong>D F</strong> are <strong>21</strong> and <strong>20</strong>, respectively, then the length of <strong>D E</strong> is <strong>29</strong> and the ratio of the length of <strong>E F</strong> to the length of <strong>D E</strong> is <strong>(21) / (29)</strong>. Thus, if <strong>tan A = (21) / (20)</strong>, the value of <strong>sin D</strong> is <strong>(21) / (29)</strong>. Note that 21/29, .7241, and 0.724 are examples of ways to enter a correct answer.",
hasFigure: false,
},
{
id: "c9931030",
type: "mcq",
questionHtml:
"<strong>R S = 20</strong><br><strong>S T = 48</strong><br><strong>T R = 52</strong><br>The side lengths of right triangle <strong>R S T</strong> are given. Triangle <strong>R S T</strong> is similar to triangle <strong>U V W</strong>, where <strong>S</strong> corresponds to <strong>V</strong> and <strong>T</strong> corresponds to <strong>W</strong>. What is the value of <strong>tan W</strong>?",
choices: [
{ label: "A", text: "<strong>five thirteenths</strong>" },
{ label: "B", text: "<strong>five twelfths</strong>" },
{ label: "C", text: "<strong>(12) / (13)</strong>" },
{ label: "D", text: "<strong>(12) / (5)</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. It's given that right triangle <strong>R S T</strong> is similar to triangle <strong>U V W</strong>, where <strong>S</strong> corresponds to <strong>V</strong> and <strong>T</strong> corresponds to <strong>W</strong>. It's given that the side lengths of the right triangle <strong>R S T</strong> are <strong>R S = 20</strong>, <strong>S T = 48</strong>, and <strong>T R = 52</strong>. Corresponding angles in similar triangles are equal. It follows that the measure of angle <strong>T</strong> is equal to the measure of angle <strong>W</strong>. The hypotenuse of a right triangle is the longest side. It follows that the hypotenuse of triangle <strong>R S T</strong> is side <strong>T R</strong>. The hypotenuse of a right triangle is the side opposite the right angle. Therefore, angle <strong>S</strong> is a right angle. The adjacent side of an acute angle in a right triangle is the side closest to the angle that is not the hypotenuse. It follows that the adjacent side of angle <strong>T</strong> is side <strong>S T</strong>. The opposite side of an acute angle in a right triangle is the side across from the acute angle. It follows that the opposite side of angle <strong>T</strong> is side <strong>R S</strong>. The tangent of an acute angle in a right triangle is the ratio of the length of the opposite side to the length of the adjacent side. Therefore, <strong>tan T = (R S) / (S T)</strong>. Substituting <strong>20</strong> for <strong>R S</strong> and <strong>48</strong> for <strong>S T</strong> in this equation yields <strong>tan T = (20) / (48)</strong>, or <strong>tan T = five twelfths</strong>. The tangents of two acute angles with equal measures are equal. Since the measure of angle <strong>T</strong> is equal to the measure of angle <strong>W</strong>, it follows that <strong>tan T = tan W</strong>. Substituting <strong>five twelfths</strong> for <strong>tan T</strong> in this equation yields <strong>five twelfths = tan W</strong>. Therefore, the value of <strong>tan W</strong> is <strong>five twelfths</strong>.<br>Choice A is incorrect. This is the value of <strong>sin W</strong>.<br>Choice C is incorrect. This is the value of <strong>cos W</strong>.<br>Choice D is incorrect. This is the value of <strong>(1) / (tan W)</strong>.",
hasFigure: false,
},
{
id: "dba6a25a",
type: "spr",
questionHtml:
"In the figure above, <strong>B D</strong> is parallel to <strong>A, E</strong>. What is the length of <strong>C E</strong> ?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 30. In the figure given, since <strong>side B D</strong> is parallel to <strong>side A, E</strong> and both segments are intersected by <strong>side C E</strong>, then angle BDC and angle AEC are corresponding angles and therefore congruent. Angle BCD and angle ACE are also congruent because they are the same angle. Triangle BCD and triangle ACE are similar because if two angles of one triangle are congruent to two angles of another triangle, the triangles are similar. Since triangle BCD and triangle ACE are similar, their corresponding sides are proportional. So in triangle BCD and triangle ACE, <strong>side B D</strong> corresponds to <strong>side A, E</strong> and <strong>side C D</strong> corresponds to <strong>side C E</strong>. Therefore, <strong>the length of side B D over the length of side C D = the length of side A, E over the length of side C E</strong>. Since triangle BCD is a right triangle, the Pythagorean theorem can be used to give the value of CD: <strong>6² + 8² = the length of side C D²</strong>. Taking the square root of each side gives <strong>the length of side C D = 10</strong>. Substituting the values in the proportion <strong>the length of side B D over the length of side C D = the length of side A, E over the length of side C E</strong> yields <strong>6 over 10 = 18 over the length of C E</strong>. Multiplying each side by CE, and then multiplying by <strong>10 over 6</strong> yields <strong>the length of side C E equal to 30</strong>. Therefore, the length of <strong>side C E</strong> is 30.",
hasFigure: true,
figureUrl: "/practice-images/dba6a25a_img1.png",
},
{
id: "f811d345",
type: "spr",
questionHtml:
"A right triangle has legs with lengths of <strong>24</strong> centimeters and <strong>21</strong> centimeters. If the length of this triangle's hypotenuse, in centimeters, can be written in the form <strong>3 √(d)</strong>, where <strong>d</strong> is an integer, what is the value of <strong>d</strong>?",
choices: [],
correctAnswer: "113",
explanation:
"The correct answer is <strong>113</strong>. It's given that the legs of a right triangle have lengths <strong>24</strong> centimeters and <strong>21</strong> centimeters. In a right triangle, the square of the length of the hypotenuse is equal to the sum of the squares of the lengths of the two legs. It follows that if <strong>h</strong> represents the length, in centimeters, of the hypotenuse of the right triangle, <strong>h² = 24² + 21²</strong>. This equation is equivalent to <strong>h² = 1, 017</strong>. Taking the square root of each side of this equation yields <strong>h = √(1, 017)</strong>. This equation can be rewritten as <strong>h = √(9 dot 113)</strong>, or <strong>h = √(9) dot √(113)</strong>. This equation is equivalent to <strong>h = 3 √(113)</strong>. It's given that the length of the triangle's hypotenuse, in centimeters, can be written in the form <strong>3 √(d)</strong>. It follows that the value of <strong>d</strong> is <strong>113</strong>.",
hasFigure: false,
},
{
id: "ffe862a3",
type: "mcq",
questionHtml:
"An isosceles right triangle has a hypotenuse of length <strong>58</strong> inches. What is the perimeter, in inches, of this triangle?",
choices: [
{ label: "A", text: "<strong>29 √(2)</strong>" },
{ label: "B", text: "<strong>58 √(2)</strong>" },
{ label: "C", text: "<strong>58 + 58 √(2)</strong>" },
{ label: "D", text: "<strong>58 + 116 √(2)</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Since the triangle is an isosceles right triangle, the two sides that form the right angle must be the same length. Let <strong>x</strong> be the length, in inches, of each of those sides. The Pythagorean theorem states that in a right triangle, <strong>a² + b² = c²</strong>, where <strong>c</strong> is the length of the hypotenuse and <strong>a</strong> and <strong>b</strong> are the lengths of the other two sides. Substituting <strong>x</strong> for <strong>a</strong>, <strong>x</strong> for <strong>b</strong>, and <strong>58</strong> for <strong>c</strong> in this equation yields <strong>x² + x² = 58²</strong>, or <strong>2 x² = 58²</strong>. Dividing each side of this equation by <strong>2</strong> yields <strong>x² = (58²) / (2)</strong>, or <strong>x² = (2 dot 58²) / (4)</strong>. Taking the square root of each side of this equation yields two solutions: <strong>x = (58 √(2)) / (2)</strong> and <strong>x = (58 √(2)) / (2)</strong>. The value of <strong>x</strong> must be positive because it represents a side length. Therefore, <strong>x = (58 √(2)) / (2)</strong>, or <strong>x = 29 √(2)</strong>. The perimeter, in inches, of the triangle is <strong>58 + x + x</strong>, or <strong>58 + 2 x</strong>. Substituting <strong>29 √(2)</strong> for <strong>x</strong> in this expression gives a perimeter, in inches, of <strong>58 + 2 (29 √(2))</strong>, or <strong>58 + 58 √(2)</strong>.<br>Choice A is incorrect. This is the length, in inches, of each of the congruent sides of the triangle, not the perimeter, in inches, of the triangle.<br>Choice B is incorrect. This is the sum of the lengths, in inches, of the congruent sides of the triangle, not the perimeter, in inches, of the triangle.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
];

View File

@ -0,0 +1,419 @@
import { type PracticeQuestion } from "../../types/lesson";
export const SAMPLE_STATS_EASY: PracticeQuestion[] = [
{
id: "0108ac2d",
type: "mcq",
questionHtml:
"At a large high school, 300 students were selected at random and were asked in a survey about a menu change in the school cafeteria. All 300 students completed the survey. It was estimated that 38% of the students were in support of a menu change, with a margin of error of 5.5%. Which of the following is the best interpretation of the survey results?",
choices: [
{
label: "A",
text: "The percent of the students at the school who support a menu change is 38%.",
},
{
label: "B",
text: "The percent of the students at the school who support a menu change is greater than 38%.",
},
{
label: "C",
text: "Plausible values of the percent of the students at the school who support a menu change are between 32.5% and 43.5%.",
},
{
label: "D",
text: "Plausible values of the number of the students at the school who support a menu change are between 295 and 305.",
},
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that an estimated 38% of sampled students at the school were in support of a menu change, with a margin of error of 5.5%. It follows that the percent of the students at the school who support a menu change is 38% plus or minus 5.5%. The lower bound of this estimation is <strong>38 5 . 5</strong>, or 32.5%. The upper bound of this estimation is <strong>38 + 5 . 5</strong>, or 43.5%. Therefore, plausible values of the percent of the students at the school who support a menu change are between 32.5% and 43.5%.Choice A is incorrect. This is the percent of the sampled students at the school who support a menu change. Choices B and D are incorrect and may result from misinterpreting the margin of error.",
hasFigure: false,
},
{
id: "6a305cd0",
type: "mcq",
questionHtml:
"In a study, the data from a random sample of a population had a mean of 37, with an associated margin of error of 3. Which of the following is the most appropriate conclusion that can be made about the population mean?",
choices: [
{ label: "A", text: "It is less than 37." },
{ label: "B", text: "It is greater than 37." },
{ label: "C", text: "It is between 34 and 40." },
{ label: "D", text: "It is less than 34 or greater than 40." },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that the mean of the data from a random sample of a population is 37, with an associated margin of error of 3. The most appropriate conclusion that can be made is that the mean of the entire population will fall between 37, plus or minus 3. Therefore, the population mean is between <strong>37 3, which = 34</strong> and <strong>37 + 3, which = 40</strong>.Choice A is incorrect. While its an appropriate conclusion that the population mean is as low as <strong>37 3</strong>, or 34, it isnt appropriate to conclude that the population mean is less than 34. Choice B is incorrect. While its an appropriate conclusion that the population mean is as high as <strong>37 + 3</strong>, or 40, it isnt appropriate to conclude that the population mean is greater than 40. Choice D is incorrect. It isnt an appropriate conclusion that the population mean is less than 34 or greater than 40.",
hasFigure: false,
},
{
id: "90eed2e5",
type: "mcq",
questionHtml:
"A city has 50 city council members. A reporter polled a random sample of 20 city council members and found that 6 of those polled supported a specific bill. Based on the sample, which of the following is the best estimate of the number of city council members in the city who support the bill?",
choices: [
{ label: "A", text: "6" },
{ label: "B", text: "9" },
{ label: "C", text: "15" },
{ label: "D", text: "30" },
],
correctAnswer: "",
explanation:
"Choice C is correct. Because a random sample of the city council was polled, the proportion of the sample who supported the bill is expected to be approximately equal to the proportion of the total city council who supports the bill. Since 6 of the 20 polled, or 30%, supported the bill, it can be estimated that <strong>50 · 0 . 3</strong>, or 15, city council members support the bill.Choice A is incorrect. This is the number of city council members in the sample who supported the bill. Choice B is incorrect and may result from a computational error. Choice D is incorrect. This is the number of city council members in the sample of city council members who were not polled.",
hasFigure: false,
},
{
id: "affb2315",
type: "mcq",
questionHtml:
"There are <strong>55</strong> students in Spanish club. A sample of the Spanish club students was selected at random and asked whether they intend to enroll in a new study program. Of those surveyed, <strong>20 % sign</strong> responded that they intend to enroll in the study program. Based on this survey, which of the following is the best estimate of the total number of Spanish club students who intend to enroll in the study program?",
choices: [
{ label: "A", text: "<strong>11</strong>" },
{ label: "B", text: "<strong>20</strong>" },
{ label: "C", text: "<strong>44</strong>" },
{ label: "D", text: "<strong>55</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that <strong>20 % sign</strong> of the students surveyed responded that they intend to enroll in the study program. Therefore, the proportion of students in Spanish club who intend to enroll in the study program, based on the survey, is <strong>0.20</strong>. Since there are <strong>55</strong> total students in Spanish club, the best estimate for the total number of these students who intend to enroll in the study program is <strong>55 (0.20)</strong>, or <strong>11</strong>.<br>Choice B is incorrect. This is the best estimate for the percentage, rather than the total number, of students in Spanish club who intend to enroll in the study program.<br>Choice C is incorrect. This is the best estimate for the total number of Spanish club students who do not intend to enroll in the study program.<br>Choice D is incorrect. This is the total number of students in Spanish club.",
hasFigure: false,
},
{
id: "e7d9649f",
type: "mcq",
questionHtml:
"A random sample of 50 people from a town with a population of 14,878 were asked to name their favorite flavor of ice cream. If 7 people in the sample named chocolate as their favorite icecream flavor, about how many people in the town would be expected to name chocolate?",
choices: [
{ label: "A", text: "350" },
{ label: "B", text: "2,100" },
{ label: "C", text: "7,500" },
{ label: "D", text: "10,500" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Let x be the number of people in the entire town that would be expected to name chocolate. Since the sample of 50 people was selected at random, it is reasonable to expect that the proportion of people who named chocolate as their favorite ice-cream flavor would be the same for both the sample and the town population. Symbolically, this can be expressed as <strong>the fraction 7 over 50, end fraction = the fraction x over 14, 878</strong>. Using cross multiplication, <strong>7 · 14, 878 = x · 50</strong>; solving for x yields 2,083. The choice closest to the value of 2,083 is choice B, 2,100.Choices A, C, and D are incorrect and may be the result of errors when setting up the proportion, solving for the unknown, or incorrectly comparing the choices to the number of people expected to name chocolate, 2,083.",
hasFigure: false,
},
{
id: "f4b3672a",
type: "mcq",
questionHtml:
"A certain forest is 253 acres. To estimate the number of trees in the forest, a ranger randomly selects 5 different 1-acre parcels in the forest and determines the number of trees in each parcel. The numbers of trees in the sample acres are 51, 59, 45, 52, and 73. Based on the mean of the sample, which of the following ranges contains the best estimate for the number of trees in the entire forest?",
choices: [
{ label: "A", text: "11,000 to 12,000" },
{ label: "B", text: "12,500 to 13,500" },
{ label: "C", text: "13,500 to 14,500" },
{ label: "D", text: "18,000 to 19,000" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The mean of the 5 samples is <strong>the fraction with numerator, 51 + 59 + 45 + 52 + 73, and denominator 5 = 56</strong> trees per acre. The best estimate for the total number of trees in the forest is the product of the mean number of trees per acre in the sample and the total number of acres in the forest. This is (56)(253) = 14,168, which is between 13,500 and 14,500.Choice A is incorrect and may result from multiplying the minimum number of trees per acre in the sample, 45, by the number of acres, 253. Choice B is incorrect and may result from multiplying the median number of trees per acre in the sample, 52, by the number of acres, 253. Choice D is incorrect and may result from multiplying the maximum number of trees per acre in the sample, 73, by the number of acres, 253.",
hasFigure: false,
},
];
export const SAMPLE_STATS_MEDIUM: PracticeQuestion[] = [
{
id: "1e562f24",
type: "mcq",
questionHtml:
"To estimate the proportion of a population that has a certain characteristic, a random sample was selected from the population. Based on the sample, it is estimated that the proportion of the population that has the characteristic is <strong>0.49</strong>, with an associated margin of error of <strong>0.04</strong>. Based on this estimate and margin of error, which of the following is the most appropriate conclusion about the proportion of the population that has the characteristic?",
choices: [
{
label: "A",
text: "It is plausible that the proportion is between <strong>0.45</strong> and <strong>0.53</strong>.",
},
{
label: "B",
text: "It is plausible that the proportion is less than <strong>0.45</strong>.",
},
{ label: "C", text: "The proportion is exactly <strong>0.49</strong>." },
{
label: "D",
text: "It is plausible that the proportion is greater than <strong>0.53</strong>.",
},
],
correctAnswer: "A",
explanation:
"Choice A is correct. Its given that the estimate for the proportion of the population that has the characteristic is <strong>0.49</strong> with an associated margin of error of <strong>0.04</strong>. Subtracting the margin of error from the estimate and adding the margin of error to the estimate gives an interval of plausible values for the true proportion of the population that has the characteristic. Therefore, its plausible that the proportion of the population that has this characteristic is between <strong>0.45</strong> and <strong>0.53</strong>.<br>Choice B is incorrect. A value less than <strong>0.45</strong> is outside the interval of plausible values for the proportion of the population that has the characteristic.<br>Choice C is incorrect. The value <strong>0.49</strong> is an estimate for the proportion based on this sample. However, since the margin of error for this estimate is known, the most appropriate conclusion is not that the proportion is exactly one value but instead lies in an interval of plausible values.<br>Choice D is incorrect. A value greater than <strong>0.53</strong> is outside the interval of plausible values for the proportion of the population that has the characteristic.",
hasFigure: false,
},
{
id: "4096a482",
type: "mcq",
questionHtml:
"Based on a random sample from a population, a researcher estimated that the mean value of a certain variable for the population is <strong>20.5</strong>, with an associated margin of error of <strong>1</strong>. Which of the following is the most appropriate conclusion?",
choices: [
{
label: "A",
text: "It is plausible that the actual mean value of the variable for the population is between <strong>19.5</strong> and <strong>21.5</strong>.",
},
{
label: "B",
text: "It is not possible that the mean value of the variable for the population is less than <strong>19.5</strong> or greater than <strong>21.5</strong>.",
},
{
label: "C",
text: "Every value of the variable in the population is between <strong>19.5</strong> and <strong>21.5</strong>.",
},
{
label: "D",
text: "The mean value of the variable for the population is <strong>20.5</strong>.",
},
],
correctAnswer: "A",
explanation:
"Choice A is correct. It's given that based on a random sample from a population, the estimated mean value for a certain variable for the population is <strong>20.5</strong>, with an associated margin of error of <strong>1</strong>. This means that it is plausible that the actual mean value of the variable for the population is between <strong>20.5 1</strong> and <strong>20.5 + 1</strong>. Therefore, the most appropriate conclusion is that it is plausible that the actual mean value of the variable for the population is between <strong>19.5</strong> and <strong>21.5</strong>.<br>Choice B is incorrect. The estimated mean value and associated margin of error describe only plausible values, not all the possible values, for the actual mean value of the variable, so this is not an appropriate conclusion.<br>Choice C is incorrect. The estimated mean value and associated margin of error describe only plausible values for the actual mean value of the variable, not all the possible values of the variable, so this is not an appropriate conclusion.<br>Choice D is incorrect. Since <strong>20.5</strong> is the estimated mean value of the variable based on a random sample, the actual mean value of the variable may not be exactly <strong>20.5</strong>. Therefore, this is not an appropriate conclusion.",
hasFigure: false,
},
{
id: "53d97af5",
type: "mcq",
questionHtml:
"A study was done on the weights of different types of fish in a pond. A random sample of fish were caught and marked in order to ensure that none were weighed more than once. The sample contained 150 largemouth bass, of which 30% weighed more than 2 pounds. Which of the following conclusions is best supported by the sample data?",
choices: [
{
label: "A",
text: "The majority of all fish in the pond weigh less than 2 pounds.",
},
{
label: "B",
text: "The average weight of all fish in the pond is approximately 2 pounds.",
},
{
label: "C",
text: "Approximately 30% of all fish in the pond weigh more than 2 pounds.",
},
{
label: "D",
text: "Approximately 30% of all largemouth bass in the pond weigh more than 2 pounds.",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. The sample of 150 largemouth bass was selected at random from all the largemouth bass in the pond, and since 30% of the fish in the sample weighed more than 2 pounds, it can be concluded that approximately 30% of all largemouth bass in the pond weigh more than 2 pounds.<br>Choices A, B, and C are incorrect. Since the sample contained 150 largemouth bass, of which 30% weighed more than 2 pounds, this result can be generalized only to largemouth bass in the pond, not to all fish in the pond.",
hasFigure: false,
},
{
id: "89f8d08a",
type: "mcq",
questionHtml:
"A store manager reviewed the receipts from 80 customers who were selected at random from all the customers who made purchases last Thursday. Of those selected, 20 receipts showed that the customer had purchased fruit. If 1,500 customers made purchases last Thursday, which of the following is the most appropriate conclusion?",
choices: [
{
label: "A",
text: "Exactly 75 customers must have purchased fruit last Thursday.",
},
{
label: "B",
text: "Exactly 375 customers must have purchased fruit last Thursday.",
},
{
label: "C",
text: "The best estimate for the number of customers who purchased fruit last Thursday is 75.",
},
{
label: "D",
text: "The best estimate for the number of customers who purchased fruit last Thursday is 375.",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. Its given that the manager took a random selection of the receipts of 80 customers from a total of 1,500. Its also given that of those 80 receipts, 20 showed that the customer had purchased fruit. This means that an appropriate estimate of the fraction of customers who purchased fruit is <strong>the fraction 20 over 80</strong>, or <strong>one fourth</strong>. Multiplying this fraction by the total number of customers yields <strong>one fourth · 1, 500 = 375</strong>. Therefore, the best estimate for the number of customers who purchased fruit is 375.Choices A and B are incorrect because an exact number of customers cant be known from taking a random selection. Additionally, choice A may also be the result of a calculation error. Choice C is incorrect and may result from a calculation error.",
hasFigure: false,
},
{
id: "9ee22c16",
type: "spr",
questionHtml:
"The town has a total of 6,000 voters. Based on the table, what is the best estimate of the number of voters who plan to vote for Candidate A?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 3,540. According to the table, of 400 voters randomly sampled, the total number of men and women who plan to vote for Candidate A is <strong>202 + 34 = 236</strong>. The best estimate of the total number of voters in the town who plan to vote for Candidate A is the fraction of voters in the sample who plan to vote for Candidate A, <strong>the fraction 236 over 400</strong>, multiplied by the total voter population of 6000. Therefore, the answer is <strong>(the fraction 236 over 400, ) · 6000 = 3540</strong>.",
hasFigure: false,
},
{
id: "e03f3477",
type: "mcq",
questionHtml:
"A sample consisting of <strong>720</strong> adults who own televisions was selected at random for a study. Based on the sample, it is estimated that <strong>32 % sign</strong> of all adults who own televisions use their televisions to watch nature shows, with an associated margin of error of <strong>3.41 % sign</strong>. Which of the following is the most plausible conclusion about all adults who own televisions?",
choices: [
{
label: "A",
text: "More than <strong>35.41 % sign</strong> of all adults who own televisions use their televisions to watch nature shows.",
},
{
label: "B",
text: "Between <strong>28.59 % sign</strong> and <strong>35.41 % sign</strong> of all adults who own televisions use their televisions to watch nature shows.",
},
{
label: "C",
text: "Since the sample included adults who own televisions and not just those who use their televisions to watch nature shows, no conclusion can be made.",
},
{
label: "D",
text: "Since the sample did not include all the people who watch nature shows, no conclusion can be made.",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. It's given that based on a sample selected at random, it's estimated that <strong>32 % sign</strong> of all adults who own televisions use their televisions to watch nature shows, with an associated margin of error of <strong>3.41 % sign</strong>. Subtracting the margin of error from the estimate and adding the margin of error to the estimate gives an interval of plausible values for the true percentage of adults who own televisions who use their televisions to watch nature shows. This means it's plausible that between <strong>32 % sign 3.41 % sign</strong>, or <strong>28.59 % sign</strong>, and <strong>32 % sign + 3.41 % sign</strong>, or <strong>35.41 % sign</strong>, of all adults who own televisions use their televisions to watch nature shows. Therefore, of the given choices, the most plausible conclusion is that between <strong>28.59 % sign</strong> and <strong>35.41 % sign</strong> of all adults who own televisions use their televisions to watch nature shows.<br>Choice A is incorrect and may result from conceptual errors.<br>Choice C is incorrect. To make a plausible conclusion about all adults who own televisions, the sample must be selected at random from all adults who own televisions, not just those who use their televisions to watch nature shows.<br>Choice D is incorrect. Since the sample was selected at random from all adults who own televisions, a plausible conclusion can be made about all adults who own televisions.",
hasFigure: false,
},
{
id: "f04d40b2",
type: "mcq",
questionHtml:
"From a population of <strong>50, 000</strong> people, <strong>1, 000</strong> were chosen at random and surveyed about a proposed piece of legislation. Based on the survey, it is estimated that <strong>35 % sign</strong> of people in the population support the legislation, with an associated margin of error of <strong>3 % sign</strong>. Based on these results, which of the following is a plausible value for the total number of people in the population who support the proposed legislation?",
choices: [
{ label: "A", text: "<strong>350</strong>" },
{ label: "B", text: "<strong>650</strong>" },
{ label: "C", text: "<strong>16, 750</strong>" },
{ label: "D", text: "<strong>31, 750</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Its given that an estimated <strong>35 % sign</strong> of people in the population support the legislation, with an associated margin of error of <strong>3 % sign</strong>. Subtracting and adding the margin of error from the estimate gives an interval of plausible values for the true percentage of people in the population who support the legislation. Therefore, its plausible that between <strong>32 % sign</strong> and <strong>38 % sign</strong> of people in this population support the legislation. The corresponding numbers of people represented by these percentages in the population can be calculated by multiplying the total population, <strong>50, 000</strong>, by <strong>0.32</strong> and by <strong>0.38</strong>, which gives <strong>50, 000 (0.32) = 16, 000</strong> and <strong>50, 000 (0.38) = 19, 000</strong>, respectively. It follows that any value in the interval <strong>16, 000</strong> to <strong>19, 000</strong> is a plausible value for the total number of people in the population who support the proposed legislation. Of the choices given, only <strong>16, 750</strong> is in this interval.<br>Choice A is incorrect. This is the number of people in the sample, rather than in the population, who support the legislation.<br>Choice B is incorrect. This is the number of people in the sample who do not support the legislation.<br>Choice D is incorrect. This is a plausible value for the total number of people in the population who do not support the proposed legislation.",
hasFigure: false,
},
{
id: "f8f79e11",
type: "mcq",
questionHtml:
"A park ranger asked a random sample of visitors how far they hiked during their visit. Based on the responses, the estimated mean was found to be 4.5 miles, with an associated margin of error of 0.5 miles. Which of the following is the best conclusion from these data?",
choices: [
{
label: "A",
text: "It is likely that all visitors hiked between 4 and 5 miles.",
},
{
label: "B",
text: "It is likely that most visitors hiked exactly 4.5 miles.",
},
{
label: "C",
text: "It is not possible that any visitor hiked less than 3 miles.",
},
{
label: "D",
text: "It is plausible that the mean distance hiked for all visitors is between 4 and 5 miles.",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. The given estimated mean has an associated margin of error because from sample data, the population mean cant be determined precisely. Rather, from the sample mean, an interval can be determined within which its plausible that the populations mean is likely to lie. Since the estimated mean is 4.5 miles with an associated margin of error of 0.5 miles, it follows that between <strong>4 . 5 0 . 5</strong> miles and <strong>4 . 5 + 0 . 5</strong> miles, or between 4 and 5 miles, is plausibly the mean distance hiked for all visitors.Choices A, B, and C are incorrect. Based on the estimated mean, no determination can be made about the number of miles hiked for all visitors to the park.",
hasFigure: false,
},
{
id: "fc46af57",
type: "mcq",
questionHtml:
"A bag containing 10,000 beads of assorted colors is purchased from a craft store. To estimate the percent of red beads in the bag, a sample of beads is selected at random. The percent of red beads in the bag was estimated to be 15%, with an associated margin of error of 2%. If r is the actual number of red beads in the bag, which of the following is most plausible?",
choices: [
{ label: "A", text: "<strong>r > 1, 700</strong>" },
{ label: "B", text: "<strong>1, 300 < r, which < 1, 700</strong>" },
{ label: "C", text: "<strong>200 < r, which < 1, 500</strong>" },
{ label: "D", text: "<strong>r < 1, 300</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. It was estimated that 15% of the beads in the bag are red. Since the bag contains 10,000 beads, it follows that there are an estimated <strong>10, 000 · 0 . 1 5 = 1, 500</strong> red beads. Its given that the margin of error is 2%, or <strong>10, 000 · 0 . 0 2 = 200</strong> beads. If the estimate is too high, there could plausibly be <strong>1, 500 200 = 1, 300</strong> red beads. If the estimate is too low, there could plausibly be <strong>1, 500 + 200 = 1, 700</strong> red beads. Therefore, the most plausible statement of the actual number of red beads in the bag is <strong>1, 300 < r, which < 1, 700</strong>.Choices A and D are incorrect and may result from misinterpreting the margin of error. Its unlikely that more than 1,700 beads or fewer than 1,300 beads in the bag are red. Choice C is incorrect because 200 is the margin of error for the number of red beads, not the lower bound of the range of red beads.",
hasFigure: false,
},
];
export const SAMPLE_STATS_HARD: PracticeQuestion[] = [
{
id: "308084c5",
type: "mcq",
questionHtml:
"The results of two random samples of votes for a proposition are shown above. The samples were selected from the same population, and the margins of error were calculated using the same method. Which of the following is the most appropriate reason that the margin of error for sample A is greater than the margin of error for sample B?",
choices: [
{
label: "A",
text: "Sample A had a smaller number of votes that could not be recorded.",
},
{
label: "B",
text: "Sample A had a higher percent of favorable responses.",
},
{ label: "C", text: "Sample A had a larger sample size." },
{ label: "D", text: "Sample A had a smaller sample size." },
],
correctAnswer: "D",
explanation:
"Choice D is correct. Sample size is an appropriate reason for the margin of error to change. In general, a smaller sample size increases the margin of error because the sample may be less representative of the whole population.Choice A is incorrect. The margin of error will depend on the size of the sample of recorded votes, not the number of votes that could not be recorded. In any case, the smaller number of votes that could not be recorded for sample A would tend to decrease, not increase, the comparative size of the margin of error. Choice B is incorrect. Since the percent in favor for sample A is the same distance from 50% as the percent in favor for sample B, the percent of favorable responses doesnt affect the comparative size of the margin of error for the two samples. Choice C is incorrect. If sample A had a larger margin of error than sample B, then sample A would tend to be less representative of the population. Therefore, sample A is not likely to have a larger sample size.",
hasFigure: false,
},
{
id: "85939da5",
type: "mcq",
questionHtml:
"In a study of cell phone use, 799 randomly selected US teens were asked how often they talked on a cell phone and about their texting behavior. The data are summarized in the table above. Based on the data from the study, an estimate of the percent of US teens who are heavy texters is 30% and the associated margin of error is 3%. Which of the following is a correct statement based on the given margin of error?",
choices: [
{
label: "A",
text: "Approximately 3% of the teens in the study who are classified as heavy texters are not really heavy texters.",
},
{
label: "B",
text: "It is not possible that the percent of all US teens who are heavy texters is less than 27%.",
},
{
label: "C",
text: "The percent of all US teens who are heavy texters is 33%.",
},
{
label: "D",
text: "It is doubtful that the percent of all US teens who are heavy texters is 35%.",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. The given margin of error of 3% indicates that the actual percent of all US teens who are heavy texters is likely within 3% of the estimate of 30%, or between 27% and 33%. Therefore, it is unlikely, or doubtful, that the percent of all US teens who are heavy texters would be 35%.Choice A is incorrect. The margin of error doesnt provide any information about the accuracy of reporting in the study. Choice B is incorrect. Based on the estimate and given margin of error, it is unlikely that the percent of all US teens who are heavy texters would be less than 27%, but it is possible. Choice C is incorrect. While the percent of all US teens who are heavy texters is likely between 27% and 33%, any value within this interval is equally likely. We cant be certain that the value is exactly 33%.",
hasFigure: false,
},
{
id: "916ffe9b",
type: "mcq",
questionHtml:
"Poll Results<br><br>Angel Cruz<br><strong>483</strong><br><br>Terry Smith<br><strong>320</strong><br><br>The table shows the results of a poll. A total of <strong>803</strong> voters selected at random were asked which candidate they would vote for in the upcoming election. According to the poll, if <strong>6, 424</strong> people vote in the election, by how many votes would Angel Cruz be expected to win?",
choices: [
{ label: "A", text: "<strong>163</strong>" },
{ label: "B", text: "<strong>1, 304</strong>" },
{ label: "C", text: "<strong>3, 864</strong>" },
{ label: "D", text: "<strong>5, 621</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. It's given that <strong>483</strong> out of <strong>803</strong> voters responded that they would vote for Angel Cruz. Therefore, the proportion of voters from the poll who responded they would vote for Angel Cruz is <strong>(483) / (803)</strong>. Its also given that there are a total of <strong>6, 424</strong> voters in the election. Therefore, the total number of people who would be expected to vote for Angel Cruz is <strong>6, 424 ((483) / (803))</strong>, or <strong>3, 864</strong>. Since <strong>3, 864</strong> of the <strong>6, 424</strong> total voters would be expected to vote for Angel Cruz, it follows that <strong>6, 424 3, 864</strong>, or <strong>2, 560</strong> voters would be expected not to vote for Angel Cruz. The difference in the number of votes for and against Angel Cruz is <strong>3, 864 2, 560</strong>, or <strong>1, 304</strong> votes. Therefore, if <strong>6, 424</strong> people vote in the election, Angel Cruz would be expected to win by <strong>1, 304</strong> votes.<br>Choice A is incorrect. This is the difference in the number of voters from the poll who responded that they would vote for and against Angel Cruz.<br>Choice C is incorrect. This is the total number of people who would be expected to vote for Angel Cruz.<br>Choice D is incorrect. This is the difference between the total number of people who vote in the election and the number of voters from the poll.",
hasFigure: false,
},
{
id: "9ba3e283",
type: "mcq",
questionHtml:
"In State X, Mr. Camps eighth-grade class consisting of 26 students was surveyed and 34.6 percent of the students reported that they had at least two siblings. The average eighthgrade class size in the state is 26. If the students in Mr. Camps class are representative of students in the states eighth-grade classes and there are 1,800 eighth-grade classes in the state, which of the following best estimates the number of eighthgrade students in the state who have fewer than two siblings?",
choices: [
{ label: "A", text: "16,200" },
{ label: "B", text: "23,400" },
{ label: "C", text: "30,600" },
{ label: "D", text: "46,800" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. It is given that 34.6% of 26 students in Mr. Camps class reported that they had at least two siblings. Since 34.6% of 26 is 8.996, there must have been 9 students in the class who reported having at least two siblings and 17 students who reported that they had fewer than two siblings. It is also given that the average eighth-grade class size in the state is 26 and that Mr. Camps class is representative of all eighth-grade classes in the state. This means that in each eighth-grade class in the state there are about 17 students who have fewer than two siblings. Therefore, the best estimate of the number of eighth-grade students in the state who have fewer than two siblings is 17 × (number of eighth-grade classes in the state), or <strong>17 · 1, 800 = 30, 600</strong>.Choice A is incorrect because 16,200 is the best estimate for the number of eighth-grade students in the state who have at least, not fewer than, two siblings. Choice B is incorrect because 23,400 is half of the estimated total number of eighth-grade students in the state; however, since the students in Mr. Camps class are representative of students in the eighth-grade classes in the state and more than half of the students in Mr. Camps class have fewer than two siblings, more than half of the students in each eighth-grade class in the state have fewer than two siblings, too. Choice D is incorrect because 46,800 is the estimated total number of eighth-grade students in the state.",
hasFigure: false,
},
{
id: "c7e73ece",
type: "spr",
questionHtml:
"A researcher interviewed 411 randomly selected US residents and asked about their views on the use of nuclear energy. The table above summarizes the responses of the interviewees. If the population of the United States was 300 million when the survey was given, based on the sample data for the 411 US residents, what is the best estimate, in millions, of the difference between the number of US residents who somewhat favor or strongly favor the use of nuclear energy and the number of those who somewhat oppose or strongly oppose it? (Round your answer to the nearest whole number.)",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 94. Of those interviewed, <strong>56 + 214 = 270</strong> “strongly favor” or “somewhat favor” the use of nuclear energy, and <strong>104 + 37 = 141</strong> interviewees “somewhat oppose” or “strongly oppose” the use of nuclear energy. The difference between the sizes of the two surveyed groups is <strong>270 141 = 129</strong>. The proportion of this difference among the entire group of interviewees is <strong>the fraction 129 over 411</strong>. Because the sample of interviewees was selected at random from US residents, it is reasonable to assume that the proportion of this difference is the same among all US residents as in the sample. Therefore, the best estimate, in millions, of the difference between the number of US residents who somewhat favor or strongly favor the use of nuclear energy and the number of those who somewhat oppose or strongly oppose it is <strong>the fraction 129 over 411, end fraction · 300</strong>, which to the nearest million is 94.",
hasFigure: false,
},
];

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,842 @@
import { type PracticeQuestion } from "../../types/lesson";
export const TWO_VAR_DATA_EASY: PracticeQuestion[] = [
{
id: "2e511919",
type: "mcq",
questionHtml:
"The line graph shows the estimated number of chipmunks in a state park on April <strong>1</strong> of each year from <strong>1989</strong> to <strong>1999</strong>.<br>The line graph:<br><br>Begins at 1989, 38 chipmunks<br>Remains level to 1990, 38 chipmunks<br>Rises sharply to 1991, 98 chipmunks <br>Rises gradually to 1992, 101 chipmunks<br>Falls sharply to 1993, 53 chipmunks<br>Rises sharply to 1994, 158 chipmunks <br>Falls sharply to 1995, 48 chipmunks <br>Rises sharply to 1996, 98 chipmunks <br>Falls gradually to 1997, 93 chipmunks<br>Falls sharply to 1998, 53 chipmunks <br>Rises sharply to 1999, 113 chipmunks<br><br>Based on the line graph, in which year was the estimated number of chipmunks in the state park the greatest?",
choices: [
{ label: "A", text: "<strong>1989</strong>" },
{ label: "B", text: "<strong>1994</strong>" },
{ label: "C", text: "<strong>1995</strong>" },
{ label: "D", text: "<strong>1998</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. For the given line graph, the estimated number of chipmunks is represented on the vertical axis. The greatest estimated number of chipmunks in the state park is indicated by the greatest height in the line graph. This height is achieved when the year is <strong>1994</strong>.<br>Choice A is incorrect and may result from conceptual errors.<br>Choice C is incorrect and may result from conceptual errors.<br>Choice D is incorrect and may result from conceptual errors.",
hasFigure: true,
figureUrl: "/practice-images/2e511919_svg1.svg",
},
{
id: "39aa146d",
type: "mcq",
questionHtml:
"The scatterplot shows the relationship between <strong>x</strong> and <strong>y</strong>. A line of best fit is also shown.<br>The scatterplot has 6 data points.<br>The data points are in a linear pattern trending up from left to right.<br>A line of best fit is shown:<br><br>The line of best fit slants up from left to right.<br>1 point is touching the line of best fit.<br>2 points are above the line of best fit.<br>3 points are below the lines of best fit.<br>The line of best fit passes through the following approximate coordinates:<br><br>(0 comma 0.2)<br>(4 comma 2)<br><br>Which of the following is closest to the slope of the line of best fit shown?",
choices: [
{ label: "A", text: "<strong>2.27</strong>" },
{ label: "B", text: "<strong>0.44</strong>" },
{ label: "C", text: "<strong>0.44</strong>" },
{ label: "D", text: "<strong>2.27</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. It's given that the scatterplot shows the relationship between two variables, <strong>x</strong> and <strong>y</strong>, and a line of best fit is shown. For the line of best fit shown, for each increase in the value of <strong>x</strong> by <strong>1</strong>, the corresponding value of <strong>y</strong> increases by a constant rate. It follows that the relationship between the variables <strong>x</strong> and <strong>y</strong> has a positive linear trend. A line in the xy-plane that passes through the points <strong>(a, b)</strong> and <strong>(c, d)</strong> has a slope of <strong>(d b) / (c a)</strong>. The line of best fit shown passes approximately through the points <strong>(0, 0.25)</strong> and <strong>(4, 2)</strong>. It follows that the slope of this line is approximately <strong>(2 0.25) / (4 0)</strong>, which is equivalent to <strong>0.4375</strong>. Therefore, of the given choices, <strong>0.44</strong> is closest to the slope of the line of best fit shown.<br>Choice A is incorrect. This is the slope of a line of best fit for a relationship between <strong>x</strong> and <strong>y</strong> that has a negative, rather than a positive, linear trend.<br>Choice B is incorrect. This is the slope of a line of best fit for a relationship between <strong>x</strong> and <strong>y</strong> that has a negative, rather than a positive, linear trend.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/39aa146d_svg1.svg",
},
{
id: "43744269",
type: "mcq",
questionHtml:
"An airplane descends from an altitude of <strong>9, 500</strong> feet to <strong>5, 000</strong> feet at a constant rate of <strong>400</strong> feet per minute. What type of function best models the relationship between the descending airplane's altitude and time?",
choices: [
{ label: "A", text: "Decreasing exponential" },
{ label: "B", text: "Decreasing linear" },
{ label: "C", text: "Increasing exponential" },
{ label: "D", text: "Increasing linear" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. Its given that the airplane descends at a constant rate of <strong>400 feet per minute</strong>. Since the altitude decreases by a constant amount during each fixed time period, the relationship between the airplanes altitude and time is linear. Since the airplane descends from an altitude of <strong>9, 500 feet</strong> to <strong>5, 000 feet</strong>, the airplanes altitude is decreasing with time. Thus, the relationship is best modeled by a decreasing linear function.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect and may result from conceptual or calculation errors.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: false,
},
{
id: "4a2264b3",
type: "mcq",
questionHtml:
"The line graph shows the percent of cars for sale at a used car lot on a given day by model year.<br>The line graph:<br><br>Begins at 2010, 12%<br>Remains level to 2011, 12%<br>Remains level to 2012, 12%<br>Falls sharply to 2013, 8%<br>Falls sharply to 2014, 4%<br>Rises sharply to 2015, 9%<br>Rises gradually to 2016, 10%<br>Remains level to 2017, 10%<br>Rises gradually to 2018, 11%<br>Remains level to 2019, 11%<br><br>For what model year is the percent of cars for sale the smallest?",
choices: [
{ label: "A", text: "<strong>2012</strong>" },
{ label: "B", text: "<strong>2013</strong>" },
{ label: "C", text: "<strong>2014</strong>" },
{ label: "D", text: "<strong>2015</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. For the given line graph, the percent of cars for sale at a used car lot on a given day is represented on the vertical axis. The percent of cars for sale is the smallest when the height of the line graph is the lowest. The lowest height of the line graph occurs for cars with a model year of <strong>2014</strong>.<br>Choice A is incorrect and may result from conceptual errors.<br>Choice B is incorrect and may result from conceptual errors.<br>Choice D is incorrect and may result from conceptual errors.",
hasFigure: true,
figureUrl: "/practice-images/4a2264b3_svg1.svg",
},
{
id: "5c24c861",
type: "mcq",
questionHtml:
"According to the model, which of the following is the best estimate for the stopping distance, in feet, if the vehicle was traveling 55 miles per hour?",
choices: [
{ label: "A", text: "25" },
{ label: "B", text: "30" },
{ label: "C", text: "210" },
{ label: "D", text: "250" },
],
correctAnswer: "C",
explanation:
"Correct Answer Rationale<br><br>Choice C is correct. According to the model, the stopping distance, in feet, of a vehicle traveling 55 miles per hour is about 200 feet. Of the choices given, the best estimate of the stopping distance for a car traveling 55 miles per hour is 210 feet.Incorrect Answer Rationale<br><br>Choices A, B, and D are incorrect and may be the result of incorrectly reading the given quadratic model. The corresponding x-values to the y-values of 25 and 30 are not part of the model. The corresponding x-value to a y-value of 250 is approximately 60 mph, not 55 mph.",
hasFigure: true,
figureUrl: "/practice-images/5c24c861_img1.png",
},
{
id: "5f3ee607",
type: "mcq",
questionHtml:
"The scatterplot has 10 data points.<br>The data points are in a linear pattern trending down from left to right.<br>Select data points have the following approximate coordinates:<br><br>(0.8 comma 8.9)<br>(2.8 comma 5.1)<br>(4.1 comma 2.9)<br><br>Which of the following equations is the most appropriate linear model for the data shown in the scatterplot?",
choices: [
{ label: "A", text: "<strong>y = 1.9 x 10.1</strong>" },
{ label: "B", text: "<strong>y = 1.9 x + 10.1</strong>" },
{ label: "C", text: "<strong>y = 1.9 x 10.1</strong>" },
{ label: "D", text: "<strong>y = 1.9 x + 10.1</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The equation representing a linear model can be written in the form <strong>y = a + b x</strong>, or <strong>y = b x + a</strong>, where <strong>b</strong> is the slope of the graph of the model and <strong>(0, a)</strong> is the y-intercept of the graph of the model. The scatterplot shows that as the x-values of the data points increase, the y-values of the data points decrease, which means the graph of an appropriate linear model has a negative slope. Therefore, <strong>b < 0</strong>. The scatterplot also shows that the data points are close to the y-axis at a positive value of <strong>y</strong>. Therefore, the y-intercept of the graph of an appropriate linear model has a positive y-coordinate, which means <strong>a > 0</strong>. Of the given choices, only choice B, <strong>y = 1.9 x + 10.1</strong>, has a negative value for <strong>b</strong>, the slope, and a positive value for <strong>a</strong>, the y-coordinate of the y-intercept. <br>Choice A is incorrect. The graph of this model has a y-intercept with a negative y-coordinate, not a positive y-coordinate.<br>Choice C is incorrect. The graph of this model has a positive slope, not a negative slope, and a y-intercept with a negative y-coordinate, not a positive y-coordinate.<br>Choice D is incorrect. The graph of this model has a positive slope, not a negative slope.",
hasFigure: true,
figureUrl: "/practice-images/5f3ee607_svg1.svg",
},
{
id: "661dfddd",
type: "mcq",
questionHtml:
"<strong>The figure presents a scatterplot titled “Temperature and Elevation.” The horizontal axis is labeled “Elevation, in feet, ” and the numbers 6, 000 through 9, 000, in increments of 500, are indicated. The vertical axis is labeled “Temperature, in ° Fahrenheit, ” and the integers 37 through 45 are indicated. There are 8 data points. The data points begin a little below, and to the right of the top of the vertical axis, then trend downward and to the right. A line of best fit is drawn. The data represented by the 8 data points are as follows. Note that all values are approximate. . 1. 6, 350 feet, 42 . 9 ° Fahrenheit. . 2. 6, 750 feet, 43 . 8 ° Fahrenheit. . 3. 6, 750 feet, 42 ° Fahrenheit. . 4. 7, 500 feet, 42 . 2 ° Fahrenheit. . 5. 8, 000 feet, 40 . 5 ° Fahrenheit. . 6. 8, 000 feet, 40 ° Fahrenheit. . 7. 8, 800 feet, 38 . 6 ° Fahrenheit. . 8. 8, 800 feet, 37 . 6 ° Fahrenheit. The line of best fit passes through the data . representing 7, 500 feet, 41 . 1 ° Fahrenheit, and the data . representing 8, 500 feet, 39 ° Fahrenheit</strong>The scatterplot above shows the high temperature on a certain day and the elevation of 8 different locations in the Lake Tahoe Basin. A line of best fit for the data is also shown. Which of the following statements best describes the association between the elevation and the temperature of locations in the Lake Tahoe Basin?",
choices: [
{
label: "A",
text: "As the elevation increases, the temperature tends to increase.",
},
{
label: "B",
text: "As the elevation increases, the temperature tends to decrease.",
},
{
label: "C",
text: "As the elevation decreases, the temperature tends to decrease.",
},
{
label: "D",
text: "There is no association between the elevation and the temperature.",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. The association between the elevation and the temperature of locations in the Lake Tahoe Basin can be described by looking at the direction of the line of best fit. The line of best fit slopes downward, which corresponds to the temperature decreasing as the elevation increases.Choices A and C are incorrect. Both of these choices would be represented by a line of best fit that slopes from the lower left to the upper right of the graph, which isnt whats shown on the graph. Choice D is incorrect. This choice would be represented by a line of best fit that is horizontal or has a slope very close to 0. This is not whats shown on the graph.",
hasFigure: true,
figureUrl: "/practice-images/661dfddd_img1.png",
},
{
id: "74dee52b",
type: "mcq",
questionHtml:
"The line graph shows the number of graduates from the classes of 2001 through 2007 at a certain school who enrolled in college within 24 months of graduation. Of the following, which class had the fewest graduates who enrolled in college within 24 months of graduation?",
choices: [
{ label: "A", text: "2002" },
{ label: "B", text: "2004" },
{ label: "C", text: "2005" },
{ label: "D", text: "2007" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The year with the fewest graduates who enrolled in college within 24 months of graduation is the point with the lowest value on the vertical axis. This occurs at 2002.Choice B, C, and D are incorrect. The years 2004, 2005, and 2007 each had a greater number of graduates who enrolled in college within 24 months of graduation than did the year 2002.",
hasFigure: true,
figureUrl: "/practice-images/74dee52b_img1.png",
},
{
id: "8156d446",
type: "spr",
questionHtml:
"<strong>The figure presents a scatterplot titled “Number of Beach Visitors versus Temperature.” The horizontal axis is labeled “Average temperature, in ° Celsius, ” and the numbers 25 through 35, in increments of 2, are indicated. The vertical axis is labeled “Number of people, ” and the numbers 0 through 640, in increments of 80, are indicated. There are 11 data points in the scatterplot that begin near the bottom left portion of the coordinate plane and trend upward and to the right. The line of best fit for the data is also shown. The line of best fit passes through 25, 80 and 32, 480.</strong>Each dot in the scatterplot above represents the temperature and the number of people who visited a beach in Lagos, Nigeria, on one of eleven different days. The line of best fit for the data is also shown. According to the line of best fit, what is the number of people, rounded to the nearest 10, predicted to visit this beach on a day with an average temperature of 32°C?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 480. An average temperature of <strong>32 ° Celsius</strong> corresponds to the value 32 on the x-axis. On the line of best fit, an x-value of 32 corresponds to a y-value of 480. The values on the y-axis correspond to the number of people predicted to visit this beach. Therefore, 480 people are predicted to visit this beach on a day with an average temperature of <strong>32 ° Celsius</strong>.",
hasFigure: true,
figureUrl: "/practice-images/8156d446_img1.png",
},
{
id: "82aaa0a1",
type: "mcq",
questionHtml:
"Of the following, which is the best model for the data in the scatterplot?",
choices: [
{ label: "A", text: "<strong>y = 2 x² 11 x 20</strong>" },
{ label: "B", text: "<strong>y = 2 x² 11 x + 20</strong>" },
{ label: "C", text: "<strong>y = 2 x² 5 x 3</strong>" },
{ label: "D", text: "<strong>y = 2 x² 5 x + 3</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The graphical model that most closely fits the data in the scatterplot is a model in which the number of data points above and below the model are approximately balanced. Fitting a graphical model to the data shown results in an upward-facing parabola with a y-intercept near <strong>0, 20</strong> and a vertex with an approximate x-value of 2.5. Of the given choices, only choice B gives an equation of an upward-facing parabola with a y-intercept at <strong>0, 20</strong>. Furthermore, substituting 2.5 for x into the equation in choice B yields <strong>y = 5</strong>. This is approximately the y-value of the vertex of the model.Choices A, C, and D are incorrect. These equations dont give a graphical model that best fits the data. At <strong>x = 0</strong>, they have y-values of <strong>20</strong>, <strong>3</strong>, and 3, respectively. At <strong>x = 2 . 5</strong>, they have y-values of <strong>35</strong>, <strong>3</strong>, and 3, respectively.",
hasFigure: true,
figureUrl: "/practice-images/82aaa0a1_img1.png",
},
{
id: "83272c51",
type: "mcq",
questionHtml:
"<strong>The figure presents a scatterplot titled “Temperature of a Cup of Coffee during an Experiment.” The horizontal axis is labeled “Time since cup was removed from heat source, in minutes, ” and the numbers 0 through 140, in increments of 20, are indicated. The vertical axis is labeled “Temperature, in ° Fahrenheit, ” and the numbers 0 through 220, in increments of 20, are indicated. There are 15 data points in the scatterplot. The data points begin with . 0, 195, and trend downward and to the right, rapidly at first, then more and more slowly, finally leveling off. The last data . is 140, 76. The 15 data points are as follows. The second coordinate of each . is approximate. . 1, 0, 195. . 2, 10, 153. . 3, 20, 136. . 4, 30, 122. . 5, 40, 109. . 6, 50, 100. . 7, 60, 92. . 8, 70, 84. . 9, 80, 82. . 10, 90, 80. . 11, 100, 79. . 12, 110, 77. . 13, 120, 77. . 14, 130, 76. . 15, 140, 76.</strong>In an experiment, a heated cup of coffee is removed from a heat source, and the cup of coffee is then left in a room that is kept at a constant temperature. The graph above shows the temperature, in degrees Fahrenheit (°F), of the coffee immediately after being removed from the heat source and at 10-minute intervals thereafter. During which of the following 10-minute intervals does the temperature of the coffee decrease at the greatest average rate?",
choices: [
{ label: "A", text: "Between 0 and 10 minutes" },
{ label: "B", text: "Between 30 and 40 minutes" },
{ label: "C", text: "Between 50 and 60 minutes" },
{ label: "D", text: "Between 90 and 100 minutes" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The average rate of change in temperature of the coffee in degrees Fahrenheit per minute is calculated by dividing the difference between two recorded temperatures by the number of minutes in the corresponding interval of time. Since the time intervals given are all 10 minutes, the average rate of change is greatest for the points with the greatest difference in temperature. Of the choices, the greatest difference in temperature occurs between 0 and 10 minutes.Choices B, C, and D are incorrect and may result from misinterpreting the average rate of change from the graph.",
hasFigure: true,
figureUrl: "/practice-images/83272c51_img1.png",
},
{
id: "8baf2118",
type: "mcq",
questionHtml:
"The scatterplot shows the relationship between two variables, <strong>x</strong> and <strong>y</strong>. A line of best fit is also shown.<br>The scatterplot has 10 data points.<br>The data points are in a linear pattern trending down from left to right.<br>A line of best fit is shown:<br><br>The line of best slants down from left to right.<br>1 point is touching the line of best fit.<br>4 points are above the line of best fit.<br>5 points are below the line of best fit.<br>The line of best fit passes through the following approximate coordinates:<br><br>(2 comma 12)<br>(8 comma 7)<br>(13 comma 3)<br><br>Which of the following equations best represents the line of best fit shown?",
choices: [
{ label: "A", text: "<strong>y = 13.5 + 0.8 x</strong>" },
{ label: "B", text: "<strong>y = 13.5 0.8 x</strong>" },
{ label: "C", text: "<strong>y = 13.5 + 0.8 x</strong>" },
{ label: "D", text: "<strong>y = 13.5 0.8 x</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The line of best fit shown intersects the y-axis at a positive y-value and has a negative slope. The graph of an equation of the form <strong>y = a + b x</strong>, where <strong>a</strong> and <strong>b</strong> are constants, intersects the y-axis at a y-value of <strong>a</strong> and has a slope of <strong>b</strong>. Of the given choices, only choice B represents a line that intersects the y-axis at a positive y-value, <strong>13.5</strong>, and has a negative slope, <strong>0.8</strong>.<br>Choice A is incorrect. This equation represents a line that has a positive slope, not a negative slope.<br>Choice C is incorrect. This equation represents a line that intersects the y-axis at a negative y-value, not a positive y-value, and has a positive slope, not a negative slope.<br>Choice D is incorrect. This equation represents a line that intersects the y-axis at a negative y-value, not a positive y-value.",
hasFigure: true,
figureUrl: "/practice-images/8baf2118_svg1.svg",
},
{
id: "9296553d",
type: "mcq",
questionHtml:
"Which of the following could be an equation for a line of best fit for the data in the scatterplot?",
choices: [
{ label: "A", text: "<strong>y = x + 6</strong>" },
{ label: "B", text: "<strong>y = x 6</strong>" },
{ label: "C", text: "<strong>y = 6 x + 1</strong>" },
{ label: "D", text: "<strong>y = 6 x 1</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. A line of best fit for the data in a scatterplot is a line that follows the trend of the data with approximately half the data points above and half the data points below the line. Based on the given data, a line of best fit will have a positive y-intercept on or near the point <strong>with coordinates 0, 6</strong> and a negative slope. All of the choices are in slope-intercept form <strong>y = m x + b</strong>, where m is the slope and b is the y-coordinate of the y-intercept. Only choice A is an equation of a line with a positive y-intercept at <strong>0, 6</strong> and a negative slope, <strong>1</strong>.Choice B is incorrect. This equation is for a line that has a negative y-intercept, not a positive y-intercept. Choices C and D are incorrect and may result from one or more sign errors and from switching the values of the y-intercept and the slope in the equation.",
hasFigure: true,
figureUrl: "/practice-images/9296553d_img1.png",
},
{
id: "9d88a3e3",
type: "mcq",
questionHtml:
"Theresa ran on a treadmill for thirty minutes, and her time and speed are shown on the graph above. According to the graph, which of the following statements is NOT true concerning Theresas run?",
choices: [
{ label: "A", text: "Theresa ran at a constant speed for five minutes." },
{
label: "B",
text: "Theresas speed was increasing for a longer period of time than it was decreasing.",
},
{
label: "C",
text: "Theresas speed decreased at a constant rate during the last five minutes.",
},
{
label: "D",
text: "Theresas speed reached its maximum during the last ten minutes.",
},
],
correctAnswer: "B",
explanation:
"Choice B is correct. Theresas speed was increasing from 0 to 5 minutes and from 20 to 25 minutes, which is a total of 10 minutes. Theresas speed was decreasing from 10 minutes to 20 minutes and from 25 to 30 minutes, which is a total of 15 minutes. Therefore, Theresas speed was NOT increasing for a longer period of time than it was decreasing.Choice A is incorrect. Theresa ran at a constant speed for the 5-minute period from 5 to 10 minutes. Choice C is incorrect. Theresas speed decreased at a constant rate during the last 5 minutes, which can be seen since the graph is linear during that time. Choice D is incorrect. Theresas speed reached its maximum at 25 minutes, which is within the last 10 minutes.",
hasFigure: true,
figureUrl: "/practice-images/9d88a3e3_img1.png",
},
{
id: "a6b2fcce",
type: "mcq",
questionHtml:
"According to the line graph above, between which two consecutive years was there the greatest change in the number of 3D movies released?",
choices: [
{ label: "A", text: "20032004" },
{ label: "B", text: "20082009" },
{ label: "C", text: "20092010" },
{ label: "D", text: "20102011" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The change in the number of 3-D movies released between any two consecutive years can be found by first estimating the number of 3-D movies released for each of the two years and then finding the positive difference between these two estimates. Between 2003 and 2004, this change is approximately <strong>2 2 = 0</strong> movies; between 2008 and 2009, this change is approximately <strong>20 8 = 12</strong> movies; between 2009 and 2010, this change is approximately <strong>26 20 = 6</strong> movies; and between 2010 and 2011, this change is approximately <strong>46 26 = 20</strong> movies. Therefore, of the pairs of consecutive years in the choices, the greatest increase in the number of 3-D movies released occurred during the time period between 2010 and 2011.Choices A, B, and C are incorrect. Between 2010 and 2011, approximately 20 more 3-D movies were released. The change in the number of 3-D movies released between any of the other pairs of consecutive years is significantly smaller than 20.",
hasFigure: true,
figureUrl: "/practice-images/a6b2fcce_img1.png",
},
{
id: "ac5b6558",
type: "mcq",
questionHtml:
"<strong>The figure presents a scatterplot titled “Temperature and Elevation.” The horizontal axis is labeled “Elevation, in feet, ” and the numbers 6, 000 through 9, 000, in increments of 500, are indicated. The vertical axis is labeled “Temperature, in ° Fahrenheit, ” and the integers 37 through 45 are indicated. There are 8 data points. The data points begin a little below, and to the right of the top of the vertical axis, then trend downward and to the right. A line of best fit is drawn. The data represented by the 8 data points are as follows. Note that all values are approximate. . 1. 6, 350 feet, 42 . 9 ° Fahrenheit. . 2. 6, 750 feet, 43 . 8 ° Fahrenheit. . 3. 6, 750 feet, 42 ° Fahrenheit. . 4. 7, 500 feet, 42 . 2 ° Fahrenheit. . 5. 8, 000 feet, 40 . 5 ° Fahrenheit. . 6. 8, 000 feet, 40 ° Fahrenheit. . 7. 8, 800 feet, 38 . 6 ° Fahrenheit. . 8. 8, 800 feet, 37 . 6 ° Fahrenheit. The line of best fit passes through the data . representing 7, 500 feet, 41 . 1 ° Fahrenheit, and the data . representing 8, 500 feet, 39 ° Fahrenheit</strong>The scatterplot above shows the high temperature on a certain day and the elevation of 8 different locations in the Lake Tahoe Basin. A line of best fit for the data is also shown. What temperature is predicted by the line of best fit for a location in the Lake Tahoe Basin with an elevation of 8,500 feet?",
choices: [
{ label: "A", text: "37°F" },
{ label: "B", text: "39°F" },
{ label: "C", text: "41°F" },
{ label: "D", text: "43°F" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The line of best fit passes through the point <strong>with coordinates 8, 500, 39</strong>. Therefore, the line of best fit predicts a temperature of 39°F for a location in Lake Tahoe Basin with an elevation of 8,500 feet.Choice A is incorrect. This is the lowest temperature listed on the scatterplot, and the line of best fit never crosses this value for any of the elevations shown. Choice C is incorrect. According to the line of best fit, the temperature of 41°F is predicted for an elevation of slightly greater than 7,500 feet, not an elevation of 8,500 feet. Choice D is incorrect. According to the line of best fit, the temperature of 43°F is predicted for an elevation of roughly 6,700 feet, not an elevation of 8,500 feet.",
hasFigure: true,
figureUrl: "/practice-images/ac5b6558_img1.png",
},
{
id: "c9dd92b1",
type: "mcq",
questionHtml:
"The densities of different concentrations of grape juice are shown in the scatterplot above. According to the trend shown by the data, which of the following is closest to the predicted density, in kilograms per cubic meter (kg/m3), for grape juice with a concentration of 60%?",
choices: [
{ label: "A", text: "1,200" },
{ label: "B", text: "1,250" },
{ label: "C", text: "1,300" },
{ label: "D", text: "1,350" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The data in the scatterplot show an increasing linear trend. The density when the juice concentration is 60% will be between the densities shown at about 53% and 67% concentration, or between about 1,255 and 1,340 kg/m3. Of the choices given, only 1,300 falls within this range.Choices A, B, and D are incorrect. These are the approximate densities of grape juice with a concentration of 45%, 55%, and 70%, respectively.",
hasFigure: true,
figureUrl: "/practice-images/c9dd92b1_img1.png",
},
{
id: "cf0ae57a",
type: "mcq",
questionHtml:
"<strong>The figure presents a scatterplot titled “Distance and Density of Planetoids in the Inner Solar System.” The horizontal axis is labeled “Distance from the Sun, ” in astronomical units (A U), and the numbers zero through 3 . 2, in increments of zero . 4, are indicated. The vertical axis is labeled “Density, ” in grams per cubic centimeter, and the numbers 3 through 6, in increments of zero . 5, are indicated. The graph has 7 data points. Three of the points are grouped in the upper left corner of the graph, below 1 . 2 A U and above 5 grams per cubic centimeter. The remaining points are above 1 . 4 A U and below 4 grams per cubic centimeter, with 3 of the points grouped in the lower right corner above 2 . 2 A U and below 3 . 7 5 grams per cubic centimeter. The line of best fit is also graphed. The line of best fit passes through the following coordinates on the grid. All data are approximate: zero A U, 5 . 7 5 grams per cubic centimeter. Zero . 8 A U; 5 grams per cubic centimeter. 1 . 6 A U; 4 . 2 5 grams per cubic centimeter. 2 . 4 A U; 3 . 5 grams per cubic centimeter. 2 . 9 A U; 3 grams per cubic centimeter.</strong>The scatterplot above shows the densities of 7 planetoids, in grams per cubic centimeter, with respect to their average distances from the Sun in astronomical units (AU). The line of best fit is also shown. An astronomer has discovered a new planetoid about 1.2 AU from the Sun. According to the line of best fit, which of the following best approximates the density of the planetoid, in grams per cubic centimeter?",
choices: [
{ label: "A", text: "3.6" },
{ label: "B", text: "4.1" },
{ label: "C", text: "4.6" },
{ label: "D", text: "5.5" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. According to the line of best fit, a planetoid with a distance from the Sun of 1.2 AU has a predicted density between <strong>4 . 5 grams per cubic centimeter</strong> and <strong>4 . 7 5 grams per cubic centimeter</strong>. The only choice in this range is 4.6.Choices A, B, and D are incorrect and may result from misreading the information in the scatterplot.",
hasFigure: true,
figureUrl: "/practice-images/cf0ae57a_img1.png",
},
{
id: "d112bc9d",
type: "mcq",
questionHtml:
"The scatterplot shows the temperature <strong>y</strong>, in <strong>° F</strong>, recorded by a meteorologist at various times <strong>x</strong>, in days since June <strong>1</strong>. <br>The scatterplot has 7 data points.<br>The data points are in a linear pattern trending approximately horizontally.<br>The data points have the following coordinates:<br><br>(1 comma 69)<br>(2 comma 60)<br>(3 comma 73)<br>(4 comma 67)<br>(5 comma 64)<br>(6 comma 62)<br>(7 comma 65)<br><br>During which of the following time periods did the greatest increase in recorded temperature take place?",
choices: [
{
label: "A",
text: "From <strong>x = 6</strong> to <strong>x = 7</strong>",
},
{
label: "B",
text: "From <strong>x = 5</strong> to <strong>x = 6</strong>",
},
{
label: "C",
text: "From <strong>x = 2</strong> to <strong>x = 3</strong>",
},
{
label: "D",
text: "From <strong>x = 1</strong> to <strong>x = 2</strong>",
},
],
correctAnswer: "C",
explanation:
"Choice C is correct. The scatterplot shows that there was an increase in recorded temperature from <strong>x = 2</strong> to <strong>x = 3</strong> and from <strong>x = 6</strong> to <strong>x = 7</strong>. When <strong>x = 2</strong>, the recorded temperature was approximately <strong>60 ° F</strong> and when <strong>x = 3</strong>, the recorded temperature was greater than <strong>70 ° F</strong>. This means that the increase in recorded temperature from <strong>x = 2</strong> to <strong>x = 3</strong> was greater than <strong>(70 60) ° F</strong>, or <strong>10 ° F</strong>. When <strong>x = 6</strong>, the recorded temperature was greater than <strong>60 ° F</strong> and when <strong>x = 7</strong>, the recorded temperature was less than <strong>70 ° F</strong>. This means that the increase in recorded temperature from <strong>x = 6</strong> to <strong>x = 7</strong> was less than <strong>(70 60) ° F</strong>, or <strong>10 ° F</strong>. It follows that the greatest increase in recorded temperature took place from <strong>x = 2</strong> to <strong>x = 3</strong>.<br>Choice A is incorrect. The increase in recorded temperature from <strong>x = 6</strong> to <strong>x = 7</strong> was less than the increase in recorded temperature from <strong>x = 2</strong> to <strong>x = 3</strong>.<br>Choice B is incorrect. From <strong>x = 5</strong> to <strong>x = 6</strong>, a decrease, not an increase, in recorded temperature took place.<br>Choice D is incorrect. From <strong>x = 1</strong> to <strong>x = 2</strong>, a decrease, not an increase, in recorded temperature took place.",
hasFigure: true,
figureUrl: "/practice-images/d112bc9d_svg1.svg",
},
{
id: "d230e963",
type: "mcq",
questionHtml:
"The scatterplot shows the relationship between two variables, <strong>x</strong> and <strong>y</strong>. A line of best fit is also shown.<br>The scatterplot has 10 data points.<br>The data points are in a linear pattern trending up from left to right.<br>A line of best fit is shown.<br><br>The line of best fit slants up from left to right.<br>1 point is touching the line of best fit.<br>5 points are above the line of best fit.<br>4 points are below the line of best fit.<br>The line of best fit passes through the following approximate coordinates:<br><br>(0 comma 3)<br>(3 comma 8)<br>(7 comma 15)<br><br>Which of the following equations best represents the line of best fit shown?",
choices: [
{ label: "A", text: "<strong>y = 2.8 + 1.7 x</strong>" },
{ label: "B", text: "<strong>y = 2.8 1.7 x</strong>" },
{ label: "C", text: "<strong>y = 2.8 + 1.7 x</strong>" },
{ label: "D", text: "<strong>y = 2.8 1.7 x</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The line of best fit shown intersects the y-axis at a positive y-value and has a positive slope. The graph of an equation of the form <strong>y = a + b x</strong>, where <strong>a</strong> and <strong>b</strong> are constants, intersects the y-axis at a y-value of <strong>a</strong> and has a slope of <strong>b</strong>. Of the given choices, only choice A represents a line that intersects the y-axis at a positive y-value, <strong>2.8</strong>, and has a positive slope, <strong>1.7</strong>.<br>Choice B is incorrect. This equation represents a line that has a negative slope, not a positive slope.<br>Choice C is incorrect. This equation represents a line that intersects the y-axis at a negative y-value, not a positive y-value.<br>Choice D is incorrect. This equation represents a line that intersects the y-axis at a negative y-value, not a positive y-value, and has a negative slope, not a positive slope.",
hasFigure: true,
figureUrl: "/practice-images/d230e963_svg1.svg",
},
{
id: "d6121490",
type: "mcq",
questionHtml:
"The graph above shows the relationship between the speed of a particular car, in miles per hour, and its corresponding braking distance, in feet. Approximately how many feet greater will the cars braking distance be when the car is traveling at 50 miles per hour than when the car is traveling at 30 miles per hour?",
choices: [
{ label: "A", text: "75" },
{ label: "B", text: "125" },
{ label: "C", text: "175" },
{ label: "D", text: "250" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. According to the graph, when the car is traveling at 50 miles per hour, the braking distance is approximately 225 feet, and when the car is traveling at 30 miles per hour, the braking distance is approximately 100 feet. The difference between these braking distances is <strong>225 100</strong>, or 125 feet.Choice A is incorrect and may result from finding the braking distance for 20 miles per hour, the difference between the given speeds. Choice C is incorrect and may result from subtracting the speed from the braking distance at 50 miles per hour. Choice D is incorrect and may result from finding the difference in the braking distances at 60 and 20 miles per hour.",
hasFigure: true,
figureUrl: "/practice-images/d6121490_img1.png",
},
];
export const TWO_VAR_DATA_MEDIUM: PracticeQuestion[] = [
{
id: "03a16790",
type: "mcq",
questionHtml:
"The scatterplot shows the relationship between two variables, <strong>x</strong> and <strong>y</strong>. A line of best fit is also shown.<br>The scatterplot has 10 data points.<br>The data points are in a linear pattern trending down from left to right.<br>A line of best fit is shown:<br><br>The line of best fit slants down from left to right.<br>2 points are touching the line of best fit.<br>3 points are above the line of best fit.<br>5 points are below the line of best fit.<br>The line of best fit passes through the following approximate coordinates:<br><br>(0 comma 12.9)<br>(6 comma 8)<br>(12 comma 3.2)<br><br>Which of the following is closest to the slope of the line of best fit shown?",
choices: [
{ label: "A", text: "<strong>2.4</strong>" },
{ label: "B", text: "<strong>0.8</strong>" },
{ label: "C", text: "<strong>0.8</strong>" },
{ label: "D", text: "<strong>2.4</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. A line of best fit is shown in the scatterplot such that as the value of <strong>x</strong> increases, the value of <strong>y</strong> decreases. Thus, the slope of the line of best fit shown is negative. The slope of a line passing through two points, <strong>(x 1, y 1)</strong> and <strong>(x 2, y 2)</strong>, can be calculated as <strong>(y 2 y 1) / (x 2 x 1)</strong>. The line of best fit shown passes approximately through the points <strong>(1, 12)</strong> and <strong>(11, 4)</strong>. Substituting <strong>(1, 12)</strong> and <strong>(11, 4)</strong> for <strong>(x 1, y 1)</strong> and <strong>(x 2, y 2)</strong>, respectively, in <strong>(y 2 y 1) / (x 2 x 1)</strong> gives <strong>(4 12) / (11 1)</strong>, which is equivalent to <strong>eight tenths</strong>, or <strong>0.8</strong>. Therefore, of the given choices, <strong>0.8</strong> is closest to the slope of the line of best fit shown.<br>Choice A is incorrect and may result from conceptual or calculation errors.<br>Choice C is incorrect. The line of best fit shown has a negative slope, not a positive slope.<br>Choice D is incorrect. The line of best fit shown has a negative slope, not a positive slope.",
hasFigure: true,
figureUrl: "/practice-images/03a16790_svg1.svg",
},
{
id: "1adb39f0",
type: "mcq",
questionHtml:
"The scatterplot shows the relationship between two variables, x and y. A line of best fit for the data is also shown. Which of the following is closest to the difference between the y-coordinate of the data point with <strong>x = 1</strong> and the y-value predicted by the line of best fit at <strong>x = 1</strong> ?<br> <strong>The figure presents a scatterplot in the xy plane. The numbers 0 through 6, in increments of 1, are indicated on the x-axis. The numbers 6 through 12, in increments of 1, are indicated on the y-axis. There are 10 data points in the scatterplot. The data points begin at 0, 12, and trend downward and to the right. The coordinates of the data points are as follows. Note that all values are approximate.<br>. 1. 0, , 12.<br>. 2. 0 . 8, , 11.<br>. 3. 1, , 12.<br>. 4. 1 . 5, , 10 . 3.<br>. 5. 2, , 10.<br>. 6. 2 . 2, , 9 . 2.<br>. 7. 3, , 9.<br>. 8. 3 . 5, , 8.<br>. 9. 3 . 8, , 8 . 3.<br>. 10. 4, , 7. A line of best fit is also drawn. The line slants downward and to the right, passing through the . with approximate coordinates 1, 11, and the . with approximate coordinates 4, 7 . 5.</strong>",
choices: [
{ label: "A", text: "1" },
{ label: "B", text: "2" },
{ label: "C", text: "5" },
{ label: "D", text: "12" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The data point with <strong>x = 1</strong> has a y-coordinate of 12. The y-value predicted by the line of best fit at <strong>x = 1</strong> is approximately 11. The difference between the y-coordinate of the data point and the y-value predicted by the line of best fit at <strong>x = 1</strong> is <strong>12 11</strong>, or 1.Choices B and C are incorrect and may result from incorrectly reading the scatterplot. Choice D is incorrect. This is the y-coordinate of the data point at <strong>x = 1</strong>.",
hasFigure: true,
figureUrl: "/practice-images/1adb39f0_img3.png",
},
{
id: "2e74e403",
type: "mcq",
questionHtml:
"In the given scatterplot, a line of best fit for the data is shown.<br>The scatterplot has 10 data points.<br>The data points are in a linear pattern trending down from left to right.<br>A line of best fit is shown:<br>The line of best fit slants down from left to right.<br><br>5 points are touching the line of best fit.<br>2 points are above the line of best fit.<br>3 points are below the line of best fit.<br>The line of best fit passes through the following approximate coordinates:<br><br>(1 comma 7)<br>(4 comma 5)<br>(10 comma 1)<br><br>Which of the following is closest to the slope of this line of best fit?",
choices: [
{ label: "A", text: "<strong>7</strong>" },
{ label: "B", text: "<strong>0.7</strong>" },
{ label: "C", text: "<strong>0.7</strong>" },
{ label: "D", text: "<strong>7</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. A line of best fit is shown in the scatterplot such that as the value of <strong>x</strong> increases, the value of <strong>y</strong> decreases. It follows that the slope of the line of best fit shown is negative. The slope of a line in the xy-plane that passes through the points <strong>(x 1, y 1)</strong> and <strong>(x 2, y 2)</strong> can be calculated as <strong>(y 2 y 1) / (x 2 x 1)</strong>. The line of best fit shown passes approximately through the points <strong>(0, 8)</strong> and <strong>(10, 1)</strong>. Substituting <strong>(0, 8)</strong> for <strong>(x 1, y 1)</strong> and <strong>(10, 1)</strong> for <strong>(x 2, y 2)</strong> in <strong>(y 2 y 1) / (x 2 x 1)</strong> yields the slope of the line being approximately <strong>(1 8) / (10 0)</strong>, which is equivalent to <strong>(7) / (10)</strong>, or <strong>0.7</strong>. Therefore, of the given choices, <strong>0.7</strong> is the closest to the slope of this line of best fit.<br>Choice A is incorrect. The line of best fit shown has a negative slope, not a positive slope.<br>Choice B is incorrect. The line of best fit shown has a negative slope, not a positive slope.<br>Choice D is incorrect and may result from conceptual or calculation errors.",
hasFigure: true,
figureUrl: "/practice-images/2e74e403_svg1.svg",
},
{
id: "3c5b19ef",
type: "mcq",
questionHtml:
"The scatterplot above shows the number of visitors to a railroad museum in Pennsylvania each year from 1968 to 1980, where t is the number of years since 1968 and n is the number of visitors. A line of best fit is also shown. Which of the following could be an equation of the line of best fit shown?",
choices: [
{ label: "A", text: "<strong>n = 16, 090 + 4, 680, t</strong>" },
{ label: "B", text: "<strong>n = 4, 690 + 16, 090, t</strong>" },
{ label: "C", text: "<strong>n = 16, 090 + 9, 060, t</strong>" },
{ label: "D", text: "<strong>n = 9, 060 + 16, 090, t</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. An equation of a line of best fit can be written in the form <strong>y = a + b x</strong>, where a is the y-intercept of the line and b is the slope. In the scatterplot shown, the line of best fit intersects the y-axis just over halfway between 10,000 and 20,000, or approximately 16,000. The line of best fit also intersects the graph at <strong>5, 40, 000</strong>. Using the slope formula <strong>b = the fraction with numerator y sub 2 y sub 1, and denominator x sub 2 x sub 1, end fraction</strong> and two points that lie on the graph such as <strong>5, 40, 000</strong> and <strong>0, 16, 000</strong>, the slope can be approximated as <strong>the fraction with numerator 40, 000 16, 000, and denominator 5 0, end fraction</strong>, or 4,800. Only choice A has a y-intercept near the estimate of 16,000 and a slope near the estimate of 4,800. Therefore, an equation of the line of best fit could be <strong>n = 16, 090 + 4, 680 t</strong>.Choice B is incorrect because the values for the slope and the y-coordinate of the y-intercept are switched. Choice C is incorrect because the value for the slope is approximately double the actual slope. Choice D is incorrect because the values for the slope and the y-intercept are switched and because the slope is approximately double the actual slope.",
hasFigure: true,
figureUrl: "/practice-images/3c5b19ef_img1.png",
},
{
id: "3d985614",
type: "mcq",
questionHtml:
"Each dot in the scatterplot above represents the height x, in feet, in the high jump, and the distance y, in feet, in the long jump, made by each student in a group of twenty students. The graph of which of the following equations is a line that most closely fits the data?",
choices: [
{ label: "A", text: "<strong>y = 0 . 8 2 x + 3 . 3 0</strong>" },
{ label: "B", text: "<strong>y = 0 . 8 2 x 0 . 8 2</strong>" },
{ label: "C", text: "<strong>y = 3 . 3 0 x + 0 . 8 2</strong>" },
{ label: "D", text: "<strong>y = 3 . 3 0 x 3 . 3 0</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. A line that most closely fits the data is a line with an approximately balanced number of data points above and below the line. Fitting a line to the data shown results in a line with an approximate slope of 3 and a y-intercept near the point <strong>with coordinates 0, 1</strong>. An equation for the line can be written in slope-intercept form, <strong>y = m x + b</strong>, where m is the slope and b is the y-coordinate of the y-intercept. The equation <strong>y = 3 . 3 0 x + 0 . 8 2</strong> in choice C fits the data most closely.Choices A and B are incorrect because the slope of the lines of these equations is 0.82, which is a value that is too small to be the slope of the line that fits the data shown. Choice D is incorrect. The graph of this equation has a y-intercept at <strong>0 3 . 3 0</strong>, not <strong>0, 0 . 8 2</strong>. This line would lie below all of the data points, and therefore would not closely fit the data.",
hasFigure: true,
figureUrl: "/practice-images/3d985614_img1.png",
},
{
id: "50b2807e",
type: "mcq",
questionHtml:
"The scatterplot shows the relationship between two variables, <strong>x</strong> and <strong>y</strong>.<br>The scatterplot has 10 data points.<br>The data points are in a linear pattern trending down from left to right.<br>The data points have the following approximate coordinates:<br><br>(0 comma 10)<br>(1.2 comma 9)<br>(2.3 comma 8)<br>(3.1 comma 5)<br>(4.8 comma 5)<br>(5.2 comma 3)<br>(6.5 comma 3)<br>(7.2 comma 3)<br>(9.6 comma 2)<br>(8.8 comma 1)<br><br>Which of the following equations is the most appropriate linear model for the data shown?",
choices: [
{ label: "A", text: "<strong>y = 0.9 + 9.4 x</strong>" },
{ label: "B", text: "<strong>y = 0.9 9.4 x</strong>" },
{ label: "C", text: "<strong>y = 9.4 + 0.9 x</strong>" },
{ label: "D", text: "<strong>y = 9.4 0.9 x</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. The data points suggest that as the variable <strong>x</strong> increases, the variable <strong>y</strong> decreases, which implies that an appropriate linear model for the data has a negative slope. The data points also show that when <strong>x</strong> is close to <strong>0</strong>, <strong>y</strong> is greater than <strong>9</strong>. Therefore, the y-intercept of the graph of an appropriate linear model has a y-coordinate greater than <strong>9</strong>. The graph of an equation of the form <strong>y = a + b x</strong>, where <strong>a</strong> and <strong>b</strong> are constants, has a y-intercept with a y-coordinate of <strong>a</strong> and has a slope of <strong>b</strong>. Of the given choices, only choice D represents a graph that has a negative slope, <strong>0.9</strong>, and a y-intercept with a y-coordinate greater than <strong>9</strong>, <strong>9.4</strong>.<br>Choice A is incorrect. The graph of this equation has a positive slope, not a negative slope, and a y-intercept with a y-coordinate less than <strong>1</strong>, not greater than <strong>9</strong>.<br>Choice B is incorrect. The graph of this equation has a y-intercept with a y-coordinate less than <strong>1</strong>, not greater than <strong>9</strong>.<br>Choice C is incorrect. The graph of this equation has a positive slope, not a negative slope.",
hasFigure: true,
figureUrl: "/practice-images/50b2807e_svg1.svg",
},
{
id: "58171b5e",
type: "mcq",
questionHtml:
"Each year, the value of an investment increases by <strong>0.49 % sign</strong> of its value the previous year. Which of the following functions best models how the value of the investment changes over time?",
choices: [
{ label: "A", text: "Decreasing exponential" },
{ label: "B", text: "Decreasing linear" },
{ label: "C", text: "Increasing exponential" },
{ label: "D", text: "Increasing linear" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. Because the value of the investment increases each year, the function that best models how the value of the investment changes over time is an increasing function. Its given that each year, the value of the investment increases by <strong>0.49 % sign</strong> of its value the previous year. Since the value of the investment changes by a fixed percentage each year, the function that best models how the value of the investment changes over time is an exponential function. Therefore, the function that best models how the value of the investment changes over time is an increasing exponential function.<br>Choice A is incorrect and may result from conceptual errors.<br>Choice B is incorrect and may result from conceptual errors.<br>Choice D is incorrect and may result from conceptual errors.",
hasFigure: false,
},
{
id: "7ac5d686",
type: "mcq",
questionHtml:
"An inspector begins a day of work with a large sample of shirts that need to be checked for defects. The inspector works at a constant rate throughout the morning. What type of model is best to model the number of shirts remaining to be checked for defects at any given time throughout the morning?",
choices: [
{ label: "A", text: "A linear model with a positive slope" },
{ label: "B", text: "A linear model with a negative slope" },
{ label: "C", text: "An exponential growth model" },
{ label: "D", text: "An exponential decay model" },
],
correctAnswer: "",
explanation:
"Choice B is correct. Since the work is done at a constant rate, a linear model best models the situation. The number of shirts remaining is dependent on the length of time the inspector has worked; therefore, if the relationship were graphed, time would be the variable of the horizontal axis and the number of remaining shirts would be the variable of the vertical axis. Since the number of shirts decreases as the time worked increases, it follows that the slope of this graph is negative.Choice A is incorrect and may result from incorrectly reasoning about the slope. Choices C and D are incorrect and may result from not identifying the constant rate of work as a characteristic of a linear model.",
hasFigure: false,
},
{
id: "7fd284ac",
type: "mcq",
questionHtml:
"The scatterplot above shows data for ten charities along with the line of best fit. For the charity with the greatest percent of total expenses spent on programs, which of the following is closest to the difference of the actual percent and the percent predicted by the line of best fit?",
choices: [
{ label: "A", text: "<strong>10 %</strong>" },
{ label: "B", text: "<strong>7 %</strong>" },
{ label: "C", text: "<strong>4 %</strong>" },
{ label: "D", text: "<strong>1 %</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. The charity with the greatest percent of total expenses spent on programs is represented by the highest point on the scatterplot; this is the point that has a vertical coordinate slightly less than halfway between 90 and 95 and a horizontal coordinate slightly less than halfway between 3,000 and 4,000. Thus, the charity represented by this point has a total income of about $3,400 million and spends about 92% of its total expenses on programs. The percent predicted by the line of best fit is the vertical coordinate of the point on the line of best fit with horizontal coordinate $3,400 million; this vertical coordinate is very slightly more than 85. Thus, the line of best fit predicts that the charity with the greatest percent of total expenses spent on programs will spend slightly more than 85% on programs. Therefore, the difference between the actual percent (92%) and the prediction (slightly more than 85%) is slightly less than 7%.Choice A is incorrect. There is no charity represented in the scatterplot for which the difference between the actual percent of total expenses spent on programs and the percent predicted by the line of best fit is as much as 10%. Choices C and D are incorrect. These choices may result from misidentifying in the scatterplot the point that represents the charity with the greatest percent of total expenses spent on programs.",
hasFigure: true,
figureUrl: "/practice-images/7fd284ac_img1.png",
},
{
id: "9a144a01",
type: "mcq",
questionHtml:
"Which of the following is true about the values of <strong>2 to the x power</strong> and <strong>2 x + 2</strong> for <strong>x > 0</strong>?",
choices: [
{
label: "A",
text: "For all <strong>x > 0</strong>, it is true that <strong>2 to the x power < 2 x + 2</strong>.",
},
{
label: "B",
text: "For all <strong>x > 0</strong>, it is true that <strong>2 to the x power > 2 x + 2</strong>.",
},
{
label: "C",
text: "There is a constant c such that if <strong>0 < x, which < c</strong>, then <strong>2 to the x power < 2 x + 2</strong>, but if <strong>x > c</strong>, then <strong>2 to the x power > 2 x + 2</strong>.",
},
{
label: "D",
text: "There is a constant c such that if <strong>0 < x, which < c</strong>, then <strong>2 to the x power > 2 x + 2</strong>, but if <strong>x > c</strong>, then <strong>2 to the x power < 2 x + 2</strong>.",
},
],
correctAnswer: "C",
explanation:
"Choice C is correct. At <strong>x = 0</strong>, the value of <strong>2 raised to the x power</strong> is less than the value of <strong>2 x + 2, where 2 to the 0 power < 2 · 0 + 2</strong>, which is equivalent to <strong>1 < 2</strong>. As the value of x increases, the value of <strong>2 raised to the x power</strong> remains less than the value of <strong>2 x + 2</strong> until <strong>x = 3</strong>, which is when the two values are equal: <strong>2³ = 2 · 3 + 2</strong>, which is equivalent to <strong>8 = 8</strong>. Then, for <strong>x > 3</strong>, the value of <strong>2 raised to the x power</strong> is greater than the value of <strong>2 x + 2</strong>. So there is a constant, 3, such that when <strong>0 < x, which < 3</strong>, then <strong>2 raised to the x power < 2 x + 2</strong>, but when <strong>x > 3</strong>, then <strong>2 raised to the x power > 2 x + 2</strong>.Choice A is incorrect because <strong>2 raised to the x power > 2 x + 2</strong> when <strong>x > 3</strong>. Choice B is incorrect because <strong>2 raised to the x power < 2 x + 2</strong> when <strong>0 < x, which < 3</strong>. Choice D is incorrect because <strong>2 raised to the x power < 2 x + 2</strong> when <strong>0 < x, which < 3</strong> and <strong>2 raised to the x power > 2 x + 2</strong> when <strong>x > 3</strong>.",
hasFigure: false,
},
{
id: "9bb4107c",
type: "spr",
questionHtml:
"In quadrant 1:<br><br>The curve begins at point (0 comma 1).<br>The curve rises sharply to point (2 comma 6).<br>The curve rises gradually to point (4 comma 7).<br>The curve rises gradually to point (6 comma 8).<br>The curve rises sharply and ends at point (8 comma 10).<br><br>The graph shows the momentum <strong>y</strong>, in newton-seconds, of an object <strong>x</strong> seconds after the object started moving, for <strong>0 < or = x < or = 8</strong>. What is the average rate of change, in newton-seconds per second, in the momentum of the object from <strong>x = 2</strong> to <strong>x = 6</strong>?",
choices: [],
correctAnswer: ".5, 1/2",
explanation:
"The correct answer is <strong>one half</strong>. For the graph shown, <strong>x</strong> represents time, in seconds, and <strong>y</strong> represents momentum, in newton-seconds. Therefore, the average rate of change, in newton-seconds per second, in the momentum of the object between two x-values is the difference in the corresponding y-values divided by the difference in the x-values. The graph shows that at <strong>x = 2</strong>, the corresponding y-value is <strong>6</strong>. The graph also shows that at <strong>x = 6</strong>, the corresponding y-value is <strong>8</strong>. It follows that the average rate of change, in newton-seconds per second, from <strong>x = 2</strong> to <strong>x = 6</strong> is <strong>(8 6) / (6 2)</strong>, which is equivalent to <strong>two fourths</strong>, or <strong>one half</strong>. Note that 1/2 and .5 are examples of ways to enter a correct answer.",
hasFigure: true,
figureUrl: "/practice-images/9bb4107c_svg1.svg",
},
{
id: "9eb896c5",
type: "mcq",
questionHtml:
"Which of the following could be the equation for a line of best fit for the data shown in the scatterplot above?",
choices: [
{ label: "A", text: "<strong>y = 3 x + 0 . 8</strong>" },
{ label: "B", text: "<strong>y = 0 . 8 x + 3</strong>" },
{ label: "C", text: "<strong>y = 0 . 8 x + 3</strong>" },
{ label: "D", text: "<strong>y = 3 x + 0 . 8</strong>" },
],
correctAnswer: "A",
explanation:
"Choice A is correct. The data show a strong linear relationship between x and y. The line of best fit for a set of data is a linear equation that minimizes the distances from the data points to the line. An equation for the line of best fit can be written in slope-intercept form, <strong>y = m x + b</strong>, where m is the slope of the graph of the line and b is the y-coordinate of the y-intercept of the graph. Since, for the data shown, the y-values increase as the x-values increase, the slope of a line of best fit must be positive. The data shown lie almost in a line, so the slope can be roughly estimated using the formula for slope, <strong>m = the fraction with numerator y sub 2 y sub 1, and denominator x sub 2 x sub 1, end fraction</strong>. The leftmost and rightmost data points have coordinates of about <strong>1, 4</strong> and <strong>8, 26</strong>, so the slope is approximately <strong>the fraction with numerator 26 4, and denominator 8 1, end fraction = the fraction 22 over 7</strong>, which is a little greater than 3. Extension of the line to the left would intersect the y-axis at about <strong>0, 1</strong>. Only choice A represents a line with a slope close to 3 and a y-intercept close to <strong>0, 1</strong>.Choice B is incorrect and may result from switching the slope and y-intercept. The line with a y-intercept of <strong>0, 3</strong> and a slope of 0.8 is farther from the data points than the line with a slope of 3 and a y-intercept of <strong>0, 0 . 8</strong>. Choices C and D are incorrect. They represent lines with negative slopes, not positive slopes.",
hasFigure: true,
figureUrl: "/practice-images/9eb896c5_img1.png",
},
{
id: "ab7740a8",
type: "mcq",
questionHtml:
"In which of the following tables is the relationship between the values of x and their corresponding y-values nonlinear?",
choices: [
{
label: "A",
text: "<strong>The answer choice presents a 2 row table, with 4 columns of data. The heading for row 1 is “x, ” and the heading for row 2 is “y.” The data in the table are as follows. Column 1. x is 1. y is 8. Column 2. x is 2. y is 11. Column 3. x is 3. y is 14. Column 4. x is 4. y is 17.</strong>",
},
{
label: "B",
text: "<strong>The answer choice presents a 2 row table, with 4 columns of data. The heading for row 1 is “x, ” and the heading for row 2 is “y.” The data in the table are as follows. Column 1. x is 1. y is 4. Column 2. x is 2. y is 8. Column 3. x is 3. y is 12. Column 4. x is 4. y is 16.</strong>",
},
{
label: "C",
text: "<strong>The answer choice presents a 2 row table, with 4 columns of data. The heading for row 1 is “x, ” and the heading for row 2 is “y.” The data in the table are as follows. Column 1. x is 1. y is 8. Column 2. x is 2. y is 13. Column 3. x is 3. y is 18. Column 4. x is 4. y is 23.</strong>",
},
{
label: "D",
text: "<strong>The answer choice presents a 2 row table, with 4 columns of data. The heading for row 1 is “x, ” and the heading for row 2 is “y.” The data in the table are as follows. Column 1. x is 1. y is 6. Column 2. x is 2. y is 12. Column 3. x is 3. y is 24. Column 4. x is 4. y is 48.</strong>",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. The relationship between the values of x and their corresponding y-values is nonlinear if the rate of change between these pairs of values isnt constant. The table for choice D gives four pairs of values: <strong>1, 6</strong>,<strong>2, 12</strong>, <strong>3, 24</strong>, and <strong>4, 48</strong>. Finding the rate of change, or slope, between <strong>1, 6</strong> and <strong>2, 12</strong> by using the slope formula, <strong>the fraction with numerator y sub 2 y sub 1, and denominator x sub 2 x sub 1, end fraction</strong>, yields <strong>the fraction with numerator 12 6, and denominator 2 1, end fraction</strong>, or 6. Finding the rate of change between <strong>2, 12</strong> and <strong>3, 24</strong> yields <strong>the fraction with numerator 24 12, and denominator 3 2, end fraction</strong>, or 12. Finding the rate of change between <strong>3, 24</strong> and <strong>4, 48</strong> yields <strong>the fraction with numerator 48 24, and denominator 4 3, end fraction</strong>, or 24. Since the rate of change isnt constant for these pairs of values, this table shows a nonlinear relationship.Choices A, B, and C are incorrect. The rate of change between the values of x and their corresponding y-values in each of these tables is constant, being 3, 4, and 5, respectively. Therefore, each of these tables shows a linear relationship.",
hasFigure: true,
figureUrl: "/practice-images/ab7740a8_img1.png",
},
{
id: "f46139df",
type: "mcq",
questionHtml:
"The scatterplot shows the relationship between two variables, <strong>x</strong> and <strong>y</strong>. A line of best fit for the data is also shown.<br>The scatterplot has 11 data points.<br>The data points are in a linear pattern trending down from left to right.<br>A line of best fit is shown:<br><br>The line of best fit slants down from left to right.<br>6 points are above the line of best fit.<br>5 points are below the line of best fit.<br>The line of best fit goes through the following approximate coordinates:<br><br>(28 comma 6)<br>(33 comma 1.5)<br><br>At <strong>x = 25.5</strong>, which of the following is closest to the y-value predicted by the line of best fit?",
choices: [
{ label: "A", text: "<strong>6.2</strong>" },
{ label: "B", text: "<strong>7.3</strong>" },
{ label: "C", text: "<strong>8.2</strong>" },
{ label: "D", text: "<strong>9.1</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. On the line of best fit, an x-value of <strong>25.5</strong> corresponds to a y-value between <strong>8</strong> and <strong>8.5</strong>. Therefore, at <strong>x = 25.5</strong>, <strong>8.2</strong> is closest to the y-value predicted by the line of best fit.<br>Choice A is incorrect and may result from conceptual errors.<br>Choice B is incorrect and may result from conceptual errors.<br>Choice D is incorrect and may result from conceptual errors.",
hasFigure: true,
figureUrl: "/practice-images/f46139df_svg1.svg",
},
{
id: "fdfc90e4",
type: "mcq",
questionHtml:
"The scatterplot shows the relationship between two variables, <strong>x</strong> and <strong>y</strong>. A line of best fit for the data is also shown.<br>The scatterplot has 11 data points.<br>The data points are in a linear pattern trending down from left to right.<br>A line of best fit is shown:<br><br>The line of best fit slants down from left to right.<br>6 points are above the line of best fit.<br>5 points are below the line of best fit.<br>The line of best fit goes through the following approximate coordinates:<br><br>(28 comma 6)<br>(33 comma 1.5)<br><br>At <strong>x = 32</strong>, which of the following is closest to the y-value predicted by the line of best fit?",
choices: [
{ label: "A", text: "<strong>0.4</strong>" },
{ label: "B", text: "<strong>1.5</strong>" },
{ label: "C", text: "<strong>2.4</strong>" },
{ label: "D", text: "<strong>3.3</strong>" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. At <strong>x = 32</strong>, the line of best fit has a y-value between <strong>2</strong> and <strong>3</strong>. The only choice with a value between <strong>2</strong> and <strong>3</strong> is choice C.<br>Choice A is incorrect. This is the difference between the y-value predicted by the line of best fit and the actual y-value at <strong>x = 32</strong> rather than the y-value predicted by the line of best fit at <strong>x = 32</strong>.<br>Choice B is incorrect. This is the y-value predicted by the line of best fit at <strong>x = 31</strong> rather than at <strong>x = 32</strong>.<br>Choice D is incorrect. This is the y-value predicted by the line of best fit at <strong>x = 33</strong> rather than at <strong>x = 32</strong>.",
hasFigure: true,
figureUrl: "/practice-images/fdfc90e4_svg1.svg",
},
];
export const TWO_VAR_DATA_HARD: PracticeQuestion[] = [
{
id: "1e1027a7",
type: "mcq",
questionHtml:
"The scatterplot above shows a companys ice cream sales d, in dollars, and the high temperature t, in degrees Celsius (°C), on 12 different days. A line of best fit for the data is also shown. Which of the following could be an equation of the line of best fit?",
choices: [
{ label: "A", text: "<strong>d = 0 . 0 3 t + 402</strong>" },
{ label: "B", text: "<strong>d = 10 t + 402</strong>" },
{ label: "C", text: "<strong>d = 33 t + 300</strong>" },
{ label: "D", text: "<strong>d = 33 t + 84</strong>" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. On the line of best fit, d increases from approximately 480 to 880 between <strong>t = 12</strong> and <strong>t = 24</strong>. The slope of the line of best fit is the difference in d-values divided by the difference in t-values, which gives <strong>the fraction with numerator 880 480, and denominator 24 12, end fraction = the fraction 400 over 12</strong>, or approximately 33. Writing the equation of the line of best fit in slope-intercept form gives <strong>d = 33 t + b</strong>, where b is the y-coordinate of the y-intercept. This equation is satisfied by all points on the line, so <strong>d = 480</strong> when <strong>t = 12</strong>. Thus, <strong>480 = 33 · 12 + b</strong>, which is equivalent to <strong>480 = 396 + b</strong>. Subtracting 396 from both sides of this equation gives <strong>b = 84</strong>. Therefore, an equation for the line of best fit could be <strong>d = 33 t + 84</strong>.Choice A is incorrect and may result from an error in calculating the slope and misidentifying the y-coordinate of the y-intercept of the graph as the value of d at [] rather than the value of d at <strong>t = 0</strong>. Choice B is incorrect and may result from using the smallest value of t on the graph as the slope and misidentifying the y-coordinate of the y-intercept of the graph as the value of d at <strong>t = 10</strong> rather than the value of d at <strong>t = 0</strong>. Choice C is incorrect and may result from misidentifying the y-coordinate of the y-intercept as the smallest value of d on the graph.",
hasFigure: true,
figureUrl: "/practice-images/1e1027a7_img1.png",
},
{
id: "79137c1b",
type: "mcq",
questionHtml:
"The scatterplot above shows the size x and the sale price y of 25 houses for sale in Town H. Which of the following could be an equation for a line of best fit for the data?",
choices: [
{ label: "A", text: "<strong>y = 200 x + 100</strong>" },
{ label: "B", text: "<strong>y = 100 x + 100</strong>" },
{ label: "C", text: "<strong>y = 50 x + 100</strong>" },
{ label: "D", text: "<strong>y = 100 x</strong>" },
],
correctAnswer: "B",
explanation:
"Choice B is correct. From the shape of the cluster of points, the line of best fit should pass roughly through the points <strong>with coordinates 1, 200</strong> and <strong>2 . 5, 350</strong>. Therefore, these two points can be used to find an approximate equation for the line of best fit. The slope of this line of best fit is therefore <strong>the fraction with numerator y sub 2 y sub 1, and denominator x sub 2 x sub 1, end fraction = the fraction with numerator 350 200, and denominator 2 . 5 1, end fraction</strong>, or 100. The equation for the line of best fit, in slope-intercept form, is <strong>y = 100 x + b</strong> for some value of b. Using the point <strong>with coordinates 1, 200</strong>, 1 can be substituted for x and 200 can be substituted for y: <strong>200 = 100 · 1 + b</strong>, or <strong>b = 100</strong>. Substituting this value into the slope-intercept form of the equation gives <strong>y = 100 x + 100</strong>.Choice A is incorrect. The line defined by <strong>y = 200 x + 100</strong> passes through the points <strong>with coordinates 1, 300</strong> and <strong>2, 500</strong>, both of which are well above the cluster of points, so it cannot be a line of best fit. Choice C is incorrect. The line defined by <strong>y = 50 x + 100</strong> passes through the points <strong>with coordinates 1, 150</strong> and <strong>2, 200</strong>, both of which lie at the bottom of the cluster of points, so it cannot be a line of best fit. Choice D is incorrect and may result from correctly calculating the slope of a line of best fit but incorrectly assuming the y-intercept is at <strong>0, 0</strong>.",
hasFigure: true,
figureUrl: "/practice-images/79137c1b_img1.png",
},
{
id: "7b52985c",
type: "spr",
questionHtml:
"The scatterplot shows the relationship between the length of time <strong>y</strong>, in hours, a certain bird spent in flight and the number of days after January <strong>11</strong>, <strong>x</strong>.<br>The scatterplot has 10 data points.<br>The data points are spread out.<br>The data points have the following coordinates:<br><br>(1 comma 14)<br>(2 comma 6)<br>(3 comma 10)<br>(4 comma 15)<br>(5 comma 14.2)<br>(6 comma 7)<br>(7 comma 11)<br>(8 comma 14)<br>(9 comma 13.5)<br>(10 comma 13.2)<br><br>What is the average rate of change, in hours per day, of the length of time the bird spent in flight on January <strong>13</strong> to the length of time the bird spent in flight on January <strong>15</strong>?",
choices: [],
correctAnswer: "4.5, 9/2",
explanation:
"The correct answer is <strong>nine halves</strong>. It's given that the scatterplot shows the relationship between the length of time <strong>y</strong>, in hours, a certain bird spent in flight and the number of days after January <strong>11</strong>, <strong>x</strong>. Since January <strong>13</strong> is <strong>2</strong> days after January <strong>11</strong>, it follows that January <strong>13</strong> corresponds to an x-value of <strong>2</strong> in the scatterplot. In the scatterplot, when <strong>x = 2</strong>, the corresponding value of <strong>y</strong> is <strong>6</strong>. In other words, on January <strong>13</strong>, the bird spent <strong>6</strong> hours in flight. Since January <strong>15</strong> is <strong>4</strong> days after January <strong>11</strong>, it follows that January <strong>15</strong> corresponds to an x-value of <strong>4</strong> in the scatterplot. In the scatterplot, when <strong>x = 4</strong>, the corresponding value of <strong>y</strong> is <strong>15</strong>. In other words, on January <strong>15</strong>, the bird spent <strong>15</strong> hours in flight. Therefore, the average rate of change, in hours per day, of the length of time the bird spent in flight on January <strong>13</strong> to the length of time the bird spent in flight on January <strong>15</strong> is the difference in the length of time, in hours, the bird spent in flight divided by the difference in the number of days after January <strong>11</strong>, or <strong>(15 6) / (4 2)</strong>, which is equivalent to <strong>nine halves</strong>. Note that 9/2 and 4.5 are examples of ways to enter a correct answer.",
hasFigure: true,
figureUrl: "/practice-images/7b52985c_svg1.svg",
},
{
id: "9b5b23fc",
type: "mcq",
questionHtml:
"For <strong>x > 0</strong>, the function <strong>f</strong> is defined as follows:<br><strong>f (x)</strong> equals <strong>201 % sign</strong> of <strong>x</strong><br>Which of the following could describe this function?",
choices: [
{ label: "A", text: "Decreasing exponential" },
{ label: "B", text: "Decreasing linear" },
{ label: "C", text: "Increasing exponential" },
{ label: "D", text: "Increasing linear" },
],
correctAnswer: "D",
explanation:
"Choice D is correct. It's given that for <strong>x > 0</strong>, <strong>f (x)</strong> is equal to <strong>201 % sign</strong> of <strong>x</strong>. This is equivalent to <strong>f (x) = (201) / (100) x</strong>, or <strong>f (x) = 2.01 x</strong>, for <strong>x > 0</strong>. This function indicates that as <strong>x</strong> increases, <strong>f (x)</strong> also increases, which means <strong>f</strong> is an increasing function. Furthermore,  <strong>f (x)</strong> increases at a constant rate of <strong>2.01</strong> for each increase of <strong>x</strong> by <strong>1</strong>. A function with a constant rate of change is linear. Thus, the function <strong>f</strong> can be described as an increasing linear function.<br>Choice A is incorrect and may result from conceptual errors.<br>Choice B is incorrect and may result from conceptual errors.<br>Choice C is incorrect. This could describe the function <strong>f (x) = (2.01)^(x)</strong>, where <strong>f (x)</strong> is equal to <strong>201 % sign</strong> of <strong>f (x 1)</strong>, not <strong>x</strong>, for <strong>x > 0</strong>.",
hasFigure: false,
},
{
id: "9d95e7ad",
type: "mcq",
questionHtml:
"<strong>The figure presents a scatterplot titled “Total Protein and Total Fat for Eight Sandwiches.” The horizontal axis is labeled “Total protein, ” in grams, and the numbers zero through 50, in increments of 10, are indicated. The vertical axis is labeled “Total fat, ” in grams, and the numbers zero through 80, in increments of 10, are indicated. Eight data points and the line of best fit are shown. The line of best fit touches all 8 data points and extends upward and to the right through the following coordinates. All data are approximate. Protein, 9 grams; Fat, 17 grams.<br>Protein, 20 grams; Fat, 33 grams.<br>Protein, 30 grams; Fat, 48 grams.<br>Protein, 40 grams; Fat, 63 grams.<br>Protein, 48 grams; Fat, 75 grams.</strong>The scatterplot above shows the numbers of grams of both total protein and total fat for eight sandwiches on a restaurant menu. The line of best fit for the data is also shown. According to the line of best fit, which of the following is closest to the predicted increase in total fat, in grams, for every increase of 1 gram in total protein?",
choices: [
{ label: "A", text: "2.5" },
{ label: "B", text: "2.0" },
{ label: "C", text: "1.5" },
{ label: "D", text: "1.0" },
],
correctAnswer: "C",
explanation:
"Choice C is correct. The predicted increase in total fat, in grams, for every increase of 1 gram in total protein is represented by the slope of the line of best fit. Any two points on the line can be used to calculate the slope of the line as the change in total fat over the change in total protein. For instance, it can be estimated that the points <strong>with coordinates 20, 34</strong> and <strong>with coordinates 30, 48</strong> are on the line of best fit, and the slope of the line that passes through them is <strong>the fraction with numerator 48 34, and denominator 30 20, end fraction = 14 over 10</strong>, or 1.4. Of the choices given, 1.5 is the closest to the slope of the line of best fit.Choices A, B, and D are incorrect and may be the result of incorrectly finding ordered pairs that lie on the line of best fit or of incorrectly calculating the slope.",
hasFigure: true,
figureUrl: "/practice-images/9d95e7ad_img1.png",
},
{
id: "af142f8d",
type: "mcq",
questionHtml:
"Two investments were made as shown in the table above. The interest in Account A is compounded once per year. Which of the following is true about the investments?",
choices: [
{
label: "A",
text: "Account A always earns more money per year than Account B.",
},
{
label: "B",
text: "Account A always earns less money per year than Account B.",
},
{
label: "C",
text: "Account A earns more money per year than Account B at first but eventually earns less money per year.",
},
{
label: "D",
text: "Account A earns less money per year than Account B at first but eventually earns more money per year.",
},
],
correctAnswer: "A",
explanation:
"Choice A is correct. Account A starts with $500 and earns interest at 6% per year, so in the first year Account A earns (500)(0.06) = $30, which is greater than the $25 that Account B earns that year. Compounding interest can be modeled by an increasing exponential function, so each year Account A will earn more money than it did the previous year. Therefore, each year Account A earns at least $30 in interest. Since Account B always earns $25 each year, Account A always earns more money per year than Account B.Choices B and D are incorrect. Account A earns $30 in the first year, which is greater than the $25 Account B earns in the first year. Therefore, neither the statement that Account A always earns less money per year than Account B nor the statement that Account A earns less money than Account B at first can be true. Choice C is incorrect. Since compounding interest can be modeled by an increasing exponential function, each year Account A will earn more money than it did the previous year. Therefore, Account A always earns at least $30 per year, which is more than the $25 per year that Account B earns.",
hasFigure: false,
},
{
id: "d0430601",
type: "spr",
questionHtml:
"<strong>The figure presents a scatterplot titled “Number of Beach Visitors versus Temperature.” The horizontal axis is labeled “Average temperature, in ° Celsius, ” and the numbers 25 through 35, in increments of 2, are indicated. The vertical axis is labeled “Number of people, ” and the numbers 0 through 640, in increments of 80, are indicated. There are 11 data points in the scatterplot that begin near the bottom left portion of the coordinate plane and trend upward and to the right. The line of best fit for the data is also shown. The line of best fit passes through 25, 80 and 32, 480.</strong><br> <br><br>Each dot in the scatterplot above represents the temperature and the number of people who visited a beach in Lagos, Nigeria, on one of eleven different days. The line of best fit for the data is also shown. The line of best fit for the data has a slope of approximately 57. According to this estimate, how many additional people per day are predicted to visit the beach for each 5°C increase in average temperature?",
choices: [],
correctAnswer: "",
explanation:
"The correct answer is 285. The number of people predicted to visit the beach each day is represented by the y-values of the line of best fit, and the average temperature, in degrees Celsius (<strong>° Celsius</strong>), is represented by the x-values. Since the slope of the line of best fit is approximately 57, the y-value, or the number of people predicted to visit the beach each day, increases by 57 for every x-value increase of 1, or every <strong>1 ° Celsius</strong> increase in average temperature. Therefore, an increase of <strong>5 ° Celsius</strong> in average temperature corresponds to a y-value increase of <strong>57 · 5 = 285</strong> additional people per day predicted to visit the beach.",
hasFigure: true,
figureUrl: "/practice-images/d0430601_img1.png",
},
{
id: "d6af3572",
type: "mcq",
questionHtml:
"<strong>The figure presents a scatterplot titled “Minimum Wage.” The x axis is labeled “Years since 1940, ” and the integers 0 through 80, in increments of 10, are indicated. The y axis is labeled “Minimum wage, in dollars per hour, ” and the integers 0 through 8 are indicated. There are 8 data points in the scatterplot, and the line of best fit is drawn. The line of best fit begins at the . representing 0 years since 1940, minimum wage 0 dollars per hour. It slants upward and to the right, and passes through the . representing 40 years since 1940, minimum wage 3 . 3 5 2 dollars, and the . representing 70 years since 1940, minimum wage 6 . 2 3 2 dollars</strong>The scatterplot above shows the federal-mandated minimum wage every 10 years between 1940 and 2010. A line of best fit is shown, and its equation is <strong>y = 0 . 0 9 6 x 0 . 4 8 8</strong>. What does the line of best fit predict about the increase in the minimum wage over the 70-year period?",
choices: [
{
label: "A",
text: "Each year between 1940 and 2010, the average increase in minimum wage was 0.096 dollars.",
},
{
label: "B",
text: "Each year between 1940 and 2010, the average increase in minimum wage was 0.49 dollars.",
},
{
label: "C",
text: "Every 10 years between 1940 and 2010, the average increase in minimum wage was 0.096 dollars.",
},
{
label: "D",
text: "Every 10 years between 1940 and 2010, the average increase in minimum wage was 0.488 dollars.",
},
],
correctAnswer: "A",
explanation:
"Choice A is correct. The given equation is in slope-intercept form, or <strong>y = m x + b</strong>, where m is the value of the slope of the line of best fit. Therefore, the slope of the line of best fit is 0.096. From the definition of slope, it follows that an increase of 1 in the x-value corresponds to an increase of 0.096 in the y-value. Therefore, the line of best fit predicts that for each year between 1940 and 2010, the minimum wage will increase by 0.096 dollar per hour.Choice B is incorrect and may result from using the y-coordinate of the y-intercept as the average increase, instead of the slope. Choice C is incorrect and may result from using the 10-year increments given on the x-axis to incorrectly interpret the slope of the line of best fit. Choice D is incorrect and may result from using the y-coordinate of the y-intercept as the average increase, instead of the slope, and from using the 10-year increments given on the x-axis to incorrectly interpret the slope of the line of best fit.",
hasFigure: true,
figureUrl: "/practice-images/d6af3572_img1.png",
},
{
id: "e821a26d",
type: "mcq",
questionHtml:
"Of the following equations, which best models the data in the scatterplot?",
choices: [
{
label: "A",
text: "<strong>y = 1 . six seven four x² + 19 . seven six x 745 . seven three</strong>",
},
{
label: "B",
text: "<strong>y = 1 . six seven four x² 19 . seven six x 745 . seven three</strong>",
},
{
label: "C",
text: "<strong>y = 1 . six seven four x² + 19 . seven six x + 745 . seven three</strong>",
},
{
label: "D",
text: "<strong>y = 1 . six seven four x² + 19 . seven six x + 745 . seven three</strong>",
},
],
correctAnswer: "D",
explanation:
"Choice D is correct. The data in the scatterplot roughly fall in the shape of a downward-opening parabola; therefore, the coefficient for the <strong>x²</strong> term must be negative. Based on the location of the data points, the y-intercept of the parabola should be somewhere between 740 and 760. Therefore, of the equations given, the best model is <strong>y = 1 . 6 7 4, x² + 19 . 7 6 x + 745 . 7 3</strong>.Choices A and C are incorrect. The positive coefficient of the <strong>x²</strong> term means that these equations each define upward-opening parabolas, whereas a parabola that fits the data in the scatterplot must open downward. Choice B is incorrect because it defines a parabola with a y-intercept that has a negative y-coordinate, whereas a parabola that fits the data in the scatterplot must have a y-intercept with a positive y-coordinate.",
hasFigure: true,
figureUrl: "/practice-images/e821a26d_img1.png",
},
];

344
src/data/questData.ts Normal file
View File

@ -0,0 +1,344 @@
import type { QuestArc } from "../types/quest";
// ─── QUEST DATA ───────────────────────────────────────────────────────────────
// Replace each node's `progress` and `status` with live API values.
// Everything else (titles, flavour, rewards) is content — edit freely.
export const QUEST_ARCS: QuestArc[] = [
// ── ARC 1: The Calm Seas ──────────────────────────────────────────────────
{
id: "east_blue",
name: "The Calm Seas",
subtitle: "Every great voyage begins at shore",
emoji: "🌊",
accentColor: "#0ea5e9",
accentDark: "#0369a1",
bgFrom: "#0c4a6e",
bgTo: "#075985",
nodes: [
{
id: "eb_1",
title: "First Steps",
flavourText:
'"I\'ll become the greatest sailor who ever lived!" — Every legend begins with a single step.',
islandName: "Hawthorn Cove",
emoji: "🏝️",
requirement: {
type: "questions",
target: 10,
label: "questions answered",
},
progress: 10,
status: "completed",
reward: { xp: 50, title: "Cabin Hand" },
},
{
id: "eb_2",
title: "Cast Off",
flavourText:
'"The sea doesn\'t care who you were — only who you become." Chart your course.',
islandName: "Redmast Port",
emoji: "⚓",
requirement: {
type: "sessions",
target: 3,
label: "practice sessions",
},
progress: 3,
status: "completed",
reward: { xp: 75 },
},
{
id: "eb_3",
title: "The Tangerine Coast",
flavourText:
'"Even alone, I protect my crew." Keep your streak burning bright.',
islandName: "Citrus Bay",
emoji: "🍊",
requirement: { type: "streak", target: 3, label: "day streak" },
progress: 3,
status: "completed",
reward: {
xp: 100,
item: "streak_shield",
itemLabel: "Streak Shield ×1",
},
},
{
id: "eb_4",
title: "The Fog Village",
flavourText:
'"I\'ve fooled everyone — except myself." Prove yourself across new territory.',
islandName: "Mistholm Village",
emoji: "🌿",
requirement: { type: "topics", target: 5, label: "topics practiced" },
progress: 3,
status: "claimable",
reward: { xp: 125, title: "Deckhand" },
},
{
id: "eb_5",
title: "The Floating Galley",
flavourText:
'"Nothing happened." Cut through the noise with razor accuracy.',
islandName: "The Iron Kitchen",
emoji: "🍖",
requirement: {
type: "accuracy",
target: 75,
label: "% accuracy (any session)",
},
progress: 58,
status: "active",
reward: {
xp: 150,
item: "xp_boost",
itemLabel: "2× XP Boost (1 session)",
},
},
{
id: "eb_6",
title: "The Sharkfin Strait",
flavourText:
'"This is my dream!" Conquer the Calm Seas before the Grand Voyage beckons.',
islandName: "Sharkfin Strait",
emoji: "🦈",
requirement: {
type: "questions",
target: 100,
label: "questions answered",
},
progress: 0,
status: "locked",
reward: { xp: 300, title: "First Mate" },
},
],
},
// ── ARC 2: The Amber Wastes ───────────────────────────────────────────────
{
id: "alabasta",
name: "The Amber Wastes",
subtitle: "Through the desert sands, to glory",
emoji: "🏜️",
accentColor: "#f59e0b",
accentDark: "#b45309",
bgFrom: "#78350f",
bgTo: "#92400e",
nodes: [
{
id: "al_1",
title: "Crossing the Mirrorlake",
flavourText:
'"A true sailor never makes excuses after losing." Enter the warzone.',
islandName: "Mirrorlake Basin",
emoji: "💧",
requirement: {
type: "sessions",
target: 5,
label: "practice sessions",
},
progress: 5,
status: "completed",
reward: { xp: 150 },
},
{
id: "al_2",
title: "The Sand March",
flavourText:
'"They underestimated us." Grind through the scorching heat.',
islandName: "The Amber Dunes",
emoji: "🌵",
requirement: {
type: "questions",
target: 50,
label: "questions answered",
},
progress: 50,
status: "completed",
reward: {
xp: 175,
item: "xp_boost",
itemLabel: "1.5× XP Boost (1 session)",
},
},
{
id: "al_3",
title: "The Sunstone Palace",
flavourText: '"I refuse to let my crew fall!" Climb the leaderboard.',
islandName: "Sunstone City",
emoji: "🏰",
requirement: {
type: "leaderboard",
target: 10,
label: "leaderboard rank",
},
progress: 22,
status: "active",
reward: { xp: 250, title: "Corsair" },
},
{
id: "al_4",
title: "Blades in the Bazaar",
flavourText:
'"I\'ll cut through iron." Maintain brutal accuracy under pressure.',
islandName: "Bazaar Streets",
emoji: "⚔️",
requirement: {
type: "accuracy",
target: 85,
label: "% accuracy (any session)",
},
progress: 0,
status: "locked",
reward: {
xp: 300,
item: "streak_shield",
itemLabel: "Streak Shield ×2",
},
},
{
id: "al_5",
title: "The Warlord Falls",
flavourText:
"\"I'm not dying here, partner.\" Prove you're worthy of the Wastes.",
islandName: "The Throne Dune",
emoji: "👑",
requirement: { type: "streak", target: 7, label: "day streak" },
progress: 0,
status: "locked",
reward: { xp: 400, title: "Corsair" },
},
{
id: "al_6",
title: "The Princess's Farewell",
flavourText:
'"Even if our paths split, you\'ll always sail with my crew." The arc is complete.',
islandName: "Mirrorlake Harbour",
emoji: "🌅",
requirement: { type: "xp", target: 1000, label: "total XP earned" },
progress: 0,
status: "locked",
reward: { xp: 500, title: "Sea Emperor" },
},
],
},
// ── ARC 3: The Sky Reaches ────────────────────────────────────────────────
{
id: "skypiea",
name: "The Sky Reaches",
subtitle: "Ascend to the island above the clouds",
emoji: "☁️",
accentColor: "#a855f7",
accentDark: "#7c3aed",
bgFrom: "#3b0764",
bgTo: "#4c1d95",
nodes: [
{
id: "sk_1",
title: "The Skyward Torrent",
flavourText:
'"The sky island is real!" Believe it — launch yourself upward.',
islandName: "Upper Cloudreach",
emoji: "🌤️",
requirement: {
type: "topics",
target: 3,
label: "topics at 70%+ accuracy",
},
progress: 0,
status: "locked",
reward: { xp: 200 },
},
{
id: "sk_2",
title: "The Trial of Storms",
flavourText:
'"Follow the wind, follow the stars." Navigate every corner of the cloudscape.',
islandName: "The Tempest Ordeal",
emoji: "🎯",
requirement: {
type: "topics",
target: 8,
label: "distinct topics practiced",
},
progress: 0,
status: "locked",
reward: {
xp: 250,
item: "xp_boost",
itemLabel: "2× XP Boost (2 sessions)",
},
},
{
id: "sk_3",
title: "The Sky God's Wrath",
flavourText: '"I am the heavens." Are you good enough to defy a deity?',
islandName: "The Celestial Ark",
emoji: "⚡",
requirement: {
type: "accuracy",
target: 90,
label: "% accuracy (any session)",
},
progress: 0,
status: "locked",
reward: { xp: 400, title: "Sea Emperor" },
},
{
id: "sk_4",
title: "The Ancient Bell",
flavourText:
'"I hear the torrent calling." Ring the bell — make history echo.',
islandName: "The Cloudvine Spire",
emoji: "🔔",
requirement: {
type: "questions",
target: 250,
label: "questions answered",
},
progress: 0,
status: "locked",
reward: {
xp: 500,
item: "streak_shield",
itemLabel: "Streak Shield ×3",
},
},
{
id: "sk_5",
title: "The Gilded Ruins",
flavourText:
'"THE GREAT CAPTAIN WAS HERE." Touch the treasure that all legends sought.',
islandName: "Aureveil",
emoji: "💰",
requirement: { type: "xp", target: 3000, label: "total XP earned" },
progress: 0,
status: "locked",
reward: { xp: 750, title: "Grand Captain" },
},
{
id: "sk_6",
title: "The Grand Captain",
flavourText:
'"This is my treasure!" You\'ve reached the summit — your target score awaits.',
islandName: "The Last Isle",
emoji: "🏴‍☠️",
requirement: {
type: "sessions",
target: 30,
label: "total sessions completed",
},
progress: 0,
status: "locked",
reward: {
xp: 1000,
title: "Grand Captain",
item: "xp_boost",
itemLabel: "Permanent 1.2× XP",
},
},
],
},
];

1960
src/data/rw/boundaries.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More