All files / web/src/components/toys/coordinate-plane/challenge answerCheck.ts

0% Statements 0/44
0% Branches 0/1
0% Functions 0/1
0% Lines 0/44

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45                                                                                         
import type { WordProblem } from '../wordProblems/types'
import type { Fraction } from '../ruler/types'
import { equationFromPoints } from '../ruler/fractionMath'

/**
 * Check if the ruler's current position matches the target equation.
 *
 * Since ruler handles snap to integer grid points, equationFromPoints produces
 * exact reduced fractions. Comparison is exact fraction equality — no floating-point
 * tolerance needed.
 */
export function checkAnswer(
  rulerAx: number,
  rulerAy: number,
  rulerBx: number,
  rulerBy: number,
  problem: WordProblem
): { correct: boolean } {
  const eq = equationFromPoints(rulerAx, rulerAy, rulerBx, rulerBy)

  // Handle degenerate ruler placements
  if (eq.kind === 'point') return { correct: false }
  if (eq.kind === 'vertical') return { correct: false }

  const target = problem.equation

  if (eq.kind === 'horizontal') {
    // y = b — slope is 0
    return {
      correct: target.slope.num === 0 && fractionsEqual({ num: eq.y, den: 1 }, target.intercept),
    }
  }

  // General case: compare slope and intercept
  return {
    correct:
      fractionsEqual(eq.slope, target.slope) && fractionsEqual(eq.intercept, target.intercept),
  }
}

function fractionsEqual(a: Fraction, b: Fraction): boolean {
  // Both are reduced fractions with positive denominators
  return a.num === b.num && a.den === b.den
}