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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | 1x 1x 1x 1x 1x 681x 681x 681x 711x 711x 711x 711x 681x 681x 1x 1x 1x 657x 656x 657x 2x 2x 2x 656x 656x 656x 1x 1x 1x 1x 1x 5x 5x 5x 5x 5x 5x 1x 1x 1x 5x 5x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 4x 1x 1x 1x 1x 1x 1x 4x 3x 3x 3x 3x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 2x 2x 2x 2x 7x 7x 7x 7x 1x 1x 1x 1x 1x 1x 1x 1x 8x 8x 1x 1x 7x 7x 8x 1x 1x 6x 6x 8x 1x 1x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x | import type { Fraction, MixedNumber, EquationForm, StandardFormCoeffs } from './types'
// ── GCD / reduce ──────────────────────────────────────────────────
export function gcd(a: number, b: number): number {
a = Math.abs(Math.floor(a))
b = Math.abs(Math.floor(b))
while (b !== 0) {
const t = b
b = a % b
a = t
}
return a
}
/** Create a reduced fraction. Denominator is always positive. */
export function fraction(num: number, den: number): Fraction {
if (den === 0) throw new Error('Division by zero')
// Normalize sign: denominator always positive
if (den < 0) {
num = -num
den = -den
}
const g = gcd(Math.abs(num), den)
return { num: num / g, den: den / g }
}
// ── Mixed number conversion ────────────────────────────────────────
/** Convert a reduced fraction to a mixed number */
export function toMixedNumber(f: Fraction): MixedNumber {
const negative = f.num < 0
const absNum = Math.abs(f.num)
const whole = Math.floor(absNum / f.den)
const fracNum = absNum % f.den
return { negative, whole, fracNum, fracDen: f.den }
}
/** True if the fraction is an integer (denominator divides numerator evenly) */
export function isInteger(f: Fraction): boolean {
return f.den === 1
}
// ── Solve for opposite variable at integer grid lines ──────────────
/**
* Given y = (slope)x + intercept, solve for y at integer x.
* y = (slope.num * x * intercept.den + intercept.num * slope.den) / (slope.den * intercept.den)
*/
export function solveForY(slope: Fraction, intercept: Fraction, x: number): Fraction {
const num = slope.num * x * intercept.den + intercept.num * slope.den
const den = slope.den * intercept.den
return fraction(num, den)
}
/**
* Given y = (slope)x + intercept, solve for x at integer y.
* x = (y * intercept.den - intercept.num) * slope.den / (intercept.den * slope.num)
*/
export function solveForX(slope: Fraction, intercept: Fraction, y: number): Fraction {
if (slope.num === 0) throw new Error('Cannot solve for x with zero slope')
const num = (y * intercept.den - intercept.num) * slope.den
const den = intercept.den * slope.num
return fraction(num, den)
}
// ── Standard form conversion ──────────────────────────────────────
/**
* Convert slope-intercept form y = (sn/sd)x + (in_/id) to standard form Ax + By = C.
*
* Multiply through by sd * id:
* sd * id * y = sn * id * x + in_ * sd
* Rearrange:
* sn*id * x − sd*id * y = −in_*sd
*
* Reduce by GCD, normalize so A > 0 (or A=0, B > 0).
*/
export function toStandardForm(slope: Fraction, intercept: Fraction): StandardFormCoeffs {
let a = slope.num * intercept.den
let b = -(slope.den * intercept.den)
let c = -(intercept.num * slope.den)
// Reduce by GCD of all three
const g = gcd(gcd(Math.abs(a), Math.abs(b)), Math.abs(c))
if (g > 0) {
a /= g
b /= g
c /= g
}
// Normalize: A > 0, or A=0 & B > 0
if (a < 0 || (a === 0 && b < 0)) {
a = -a
b = -b
c = -c
}
// Avoid -0
return { a: a || 0, b: b || 0, c: c || 0 }
}
// ── Equation from two points ───────────────────────────────────────
/**
* Compute the linear equation form for the line through (x1, y1) and (x2, y2).
* All inputs must be integers.
*/
export function equationFromPoints(x1: number, y1: number, x2: number, y2: number): EquationForm {
// Same point
if (x1 === x2 && y1 === y2) {
return { kind: 'point', x: x1, y: y1 }
}
// Vertical line
if (x1 === x2) {
return { kind: 'vertical', x: x1 }
}
// Horizontal line
if (y1 === y2) {
return { kind: 'horizontal', y: y1 }
}
// General case: slope = (y2 - y1) / (x2 - x1)
const dy = y2 - y1
const dx = x2 - x1
const slope = fraction(dy, dx)
// intercept = y1 - slope * x1 = (y1 * dx - dy * x1) / dx
const interceptNum = y1 * dx - dy * x1
const intercept = fraction(interceptNum, dx)
return { kind: 'general', slope, intercept }
}
|