Compare commits
5 Commits
c69e6ab7c1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 45a11a379a | |||
| 8a7b952deb | |||
| 540fdb208c | |||
| f2e29f2735 | |||
| 97c0fb7f8e |
12
README.md
12
README.md
@@ -1,7 +1,15 @@
|
||||
GCF (and LCM) Practice
|
||||
GCF/LCM/Multiplication Practice
|
||||
===
|
||||
This is a simple app to practice on greatest common factor (GCF) and least
|
||||
common multiple (LCM) math problems.
|
||||
common multiple (LCM) math problems, as well as simple multiplication. It
|
||||
was created to help a primary school student practice math skills. Solutions
|
||||
are provided on request.
|
||||
|
||||
While the defaults for GCF and LCM (pairs of positive integers up to 200) may
|
||||
seem large for such a young learner, the app demonstrates how to apply Euclid's
|
||||
algorithm, which requires only a knowledge of integer division with remainders,
|
||||
to calculate GCF. Numeric values are color coded so that the student can follow
|
||||
each step of the calculation.
|
||||
|
||||
Compiling
|
||||
---
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
"react-bootstrap": "^2.10.1",
|
||||
"react-dom": "npm:@preact/compat",
|
||||
"react-router": "^6.22.2",
|
||||
"react-router-dom": "^6.22.2"
|
||||
"react-router-dom": "^6.22.2",
|
||||
"rollup": "npm:@rollup/wasm-node"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@preact/preset-vite": "^2.8.1",
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
|
||||
.no-arrows::-webkit-outer-spin-button,
|
||||
.no-arrows::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
-webkit-appearance: none !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.no-arrows {
|
||||
-moz-appearance: textfield;
|
||||
-moz-appearance: textfield !important;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export function App() {
|
||||
<Navbar maxNum={maxNum} onMaxNumChanged={onMaxNumSet} />
|
||||
<Routes>
|
||||
<Route path="/" element={<Navigate to="/gcf" />} />
|
||||
<Route path="/gcf" element={<GCF />} />
|
||||
<Route path="/gcf" element={<GCF maxNum={maxNum} />} />
|
||||
<Route path="/times" element={<TimesPractice maxNum={12} />} />
|
||||
<Route path="/lcm" element={<LCM />} />
|
||||
</Routes>
|
||||
|
||||
22
src/gcf.tsx
22
src/gcf.tsx
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'preact/hooks'
|
||||
import { useState, useEffect } from 'preact/hooks'
|
||||
import './gcf.css'
|
||||
import { gcf } from './lib'
|
||||
import type { JSX } from 'preact'
|
||||
@@ -37,15 +37,17 @@ function Solution({rows}:SolutionParams) {
|
||||
</div>
|
||||
}
|
||||
|
||||
const DEFAULT_MAXNUM = 200
|
||||
|
||||
export function GCF() {
|
||||
|
||||
export function GCF({ maxNum } : { maxNum? : number }) {
|
||||
// choose number between 2 and max inclusive
|
||||
const getRandomInt = (max : number) : number => Math.floor(Math.random() * (max - 1) + 2)
|
||||
|
||||
const chooseFactorsRandom = () : [number, number] => [ getRandomInt(200), getRandomInt(200) ]
|
||||
const chooseFactorsRandom = () : [number, number] => [ getRandomInt(maxNum || DEFAULT_MAXNUM), getRandomInt(maxNum || DEFAULT_MAXNUM) ]
|
||||
|
||||
const _chooseMultiplesOf = (f : number) : [number, number] => {
|
||||
const max = Math.floor(200 / f)
|
||||
const max = Math.floor((maxNum || DEFAULT_MAXNUM) / f)
|
||||
return [ f * getRandomInt(max), f * getRandomInt(max) ]
|
||||
}
|
||||
|
||||
@@ -54,7 +56,7 @@ export function GCF() {
|
||||
}
|
||||
|
||||
const chooseMultiples = () : [number, number] => {
|
||||
const f = getRandomInt(50)
|
||||
const f = getRandomInt(Math.min(50, Math.floor((maxNum || DEFAULT_MAXNUM) / 2)))
|
||||
return _chooseMultiplesOf(f)
|
||||
}
|
||||
|
||||
@@ -135,6 +137,16 @@ export function GCF() {
|
||||
const [feedback, setFeedback] = useState(false)
|
||||
const [solution, setSolution] = useState<JSX.Element|null>(null)
|
||||
|
||||
useEffect(()=>{
|
||||
if (maxNum) {
|
||||
if ((factors[0] > maxNum) || (factors[1] > maxNum)) {
|
||||
// don't change unless new constraint violated
|
||||
setFactors(chooseFactors())
|
||||
}
|
||||
}
|
||||
}, [ maxNum ])
|
||||
|
||||
|
||||
return (
|
||||
<div className="px-4 py-5 my-5 text-center">
|
||||
<h1 className="my-5 d-none d-sm-block">Greatest Common Factor Practice</h1>
|
||||
|
||||
@@ -46,7 +46,7 @@ function Navbar({maxNum, onMaxNumChanged} : NavbarSettings) {
|
||||
<div className="nav-item ms-auto me-6 g-3 row align-items-center">
|
||||
<label className="col-form-label col-sm-4 col-form-label-sm ge-2 flex-shrink-0" for="maxNum">Max:</label>
|
||||
<div className="col-sm-4 flex-shrink-0">
|
||||
<input className="form-range" type="range" id="maxNum" step={10} value={maxNum} max={200} min={50} onInput={handleSliderInput} onChange={onSliderChange} />
|
||||
<input className="form-range" type="range" id="maxNum" step={10} value={displayedMax} max={200} min={50} onMouseUp={handleSliderInput} onKeyUp={handleSliderInput} onChange={onSliderChange} />
|
||||
</div>
|
||||
<label className="col-form-label col-sm-2 ms-auto">{displayedMax}</label>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useState } from 'preact/hooks'
|
||||
import './times.css'
|
||||
import type { JSX } from 'preact'
|
||||
|
||||
interface TimesPracticeParams {
|
||||
maxNum : number
|
||||
|
||||
Reference in New Issue
Block a user