Add LCM practice
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
/*max-width: 1280px;*/
|
||||
width:100%;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
/*padding: 2rem;*/
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
142
src/app.tsx
142
src/app.tsx
@@ -1,132 +1,18 @@
|
||||
import { useState } from 'preact/hooks'
|
||||
import { GCF } from './gcf'
|
||||
import { LCM } from './lcm'
|
||||
import Navbar from './navbar'
|
||||
import { BrowserRouter, Navigate, Routes, Route } from 'react-router-dom'
|
||||
import './app.css'
|
||||
import { Solution } from './solution'
|
||||
import type { SolutionKey } from './solution'
|
||||
import type { JSX } from 'preact'
|
||||
|
||||
export function App() {
|
||||
// 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 _chooseMultiplesOf = (f : number) : [number, number] => {
|
||||
const max = Math.floor(200 / f)
|
||||
return [ f * getRandomInt(max), f * getRandomInt(max) ]
|
||||
}
|
||||
|
||||
const chooseMultiplesOf = (f : number) : () => [ number, number ] => {
|
||||
return () => _chooseMultiplesOf(f)
|
||||
}
|
||||
|
||||
const chooseMultiples = () : [number, number] => {
|
||||
const f = getRandomInt(50)
|
||||
return _chooseMultiplesOf(f)
|
||||
}
|
||||
|
||||
const chooseFactors = () : [number, number] => {
|
||||
const probabilities : Array<[number, () => [number, number]]>= [
|
||||
[ 0.2, chooseFactorsRandom ],
|
||||
[ 0.2, chooseMultiples ],
|
||||
[ 0.2, chooseMultiplesOf(3) ],
|
||||
[ 0.2, chooseMultiplesOf(7) ],
|
||||
[ 0.1, chooseMultiplesOf(11) ],
|
||||
[ 0.1, chooseMultiplesOf(17) ],
|
||||
]
|
||||
const r = Math.random()
|
||||
var i = 0, accum = 0
|
||||
for (i = 0; i < probabilities.length; i++) {
|
||||
console.log([r, i, accum, probabilities[i]])
|
||||
if ((r > accum) && (r <= accum + probabilities[i][0])) break
|
||||
accum += probabilities[i][0]
|
||||
}
|
||||
if (i >= probabilities.length) i = probabilities.length - 1
|
||||
return probabilities[i][1]()
|
||||
}
|
||||
|
||||
const gcd = (a : number, b : number) : number => {
|
||||
if (b > a) return gcd(b, a)
|
||||
else if (b == 0) return a
|
||||
else return gcd(b, a % b)
|
||||
}
|
||||
|
||||
const getSolution = (a : number, b : number) : SolutionKey => {
|
||||
var result : SolutionKey = [ ]
|
||||
if (b > a) {
|
||||
var t = b
|
||||
b = a
|
||||
a = t
|
||||
}
|
||||
while (b != 0) {
|
||||
result.push([ a, Math.floor(a / b), b, a % b ])
|
||||
var t = a % b
|
||||
a = b
|
||||
b = t
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const doCheck = (e : Event) : void => {
|
||||
e.preventDefault()
|
||||
const rightAnswer = gcd(factors[0], factors[1])
|
||||
const yourAnswer = (document.getElementById("inlineFormInputResponse") as HTMLInputElement).value
|
||||
if (rightAnswer == Number(yourAnswer)) {
|
||||
setCorrect(true)
|
||||
setFeedback(true)
|
||||
} else {
|
||||
setFeedback(true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const doNext = (e : Event) : void => {
|
||||
e.preventDefault()
|
||||
setFeedback(false)
|
||||
setCorrect(false)
|
||||
setFactors(chooseFactors())
|
||||
setSolution(null)
|
||||
document.forms[0].reset()
|
||||
}
|
||||
|
||||
const doSolution = (e : Event) : void => {
|
||||
e.preventDefault()
|
||||
if (solution === null) {
|
||||
var answerBox = document.getElementById("inlineFormInputResponse") as HTMLInputElement
|
||||
answerBox.value = String(gcd(factors[0], factors[1]))
|
||||
setSolution(<Solution rows={getSolution(factors[0], factors[1])} />)
|
||||
setCorrect(true)
|
||||
//setFeedback(true)
|
||||
} else {
|
||||
setSolution(null)
|
||||
}
|
||||
}
|
||||
|
||||
const [factors, setFactors] = useState(chooseFactors())
|
||||
|
||||
const [correct, setCorrect] = useState(false)
|
||||
const [feedback, setFeedback] = useState(false)
|
||||
const [solution, setSolution] = useState<JSX.Element|null>(null)
|
||||
|
||||
return (
|
||||
<div className="px-4 py-5 my-5 text-center">
|
||||
<h1 className="my-5">Greatest Common Factor Practice</h1>
|
||||
<p className="fs-3">What is the greatest common factor of <mark>{factors[0]}</mark> and <mark>{factors[1]}</mark>?</p>
|
||||
<form className="row row-cols-lg-auto g-3 align-items-center justify-content-center">
|
||||
<div className="col-12">
|
||||
<label className="visually-hidden" for="inlineFormInputResponse">Response</label>
|
||||
<div className="input-group">
|
||||
<input type="text" size={3} autocomplete="off" className="form-control text-center" id="inlineFormInputResponse" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<button type="submit" onClick={correct ? doNext : doCheck} className="btn btn-primary">{correct ? "Next" : "Check"}</button>
|
||||
<button type="submit" onClick={doSolution} className="ms-2 btn btn-secondary">{solution !== null ? "Hide" : "Solve"}</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className={feedback ? "visible" : "invisible"}>
|
||||
<div className={correct ? "alert alert-success m-4" : "alert alert-danger m-4"}>{correct ? "Correct" : "Try again!"}</div>
|
||||
</div>
|
||||
{solution !== null ? solution : <></>}
|
||||
</div>
|
||||
)
|
||||
return <>
|
||||
<BrowserRouter>
|
||||
<Navbar />
|
||||
<Routes>
|
||||
<Route path="/" element={<Navigate to="/gcf" />} />
|
||||
<Route path="/gcf" element={<GCF />} />
|
||||
<Route path="/lcm" element={<LCM />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</>
|
||||
}
|
||||
|
||||
154
src/gcf.tsx
Normal file
154
src/gcf.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
import { useState } from 'preact/hooks'
|
||||
import './gcf.css'
|
||||
import { gcf } from './lib'
|
||||
import type { JSX } from 'preact'
|
||||
|
||||
type SolutionRow = [Number, Number, Number, Number]
|
||||
type SolutionKey = Array<SolutionRow>
|
||||
type SolutionParams = {
|
||||
rows : SolutionKey
|
||||
}
|
||||
|
||||
function Solution({rows}:SolutionParams) {
|
||||
const colors = [
|
||||
"red",
|
||||
"blue",
|
||||
"green",
|
||||
"brown",
|
||||
"purple",
|
||||
"orange"
|
||||
]
|
||||
const displayRow = (row : SolutionRow, index : number) => {
|
||||
let range : number[] = [0, 1, 2]
|
||||
const styles = range.map((i)=>{return `padding:3px;color:white;background:${colors[(i+index)%colors.length]}`})
|
||||
return <p>
|
||||
<span style={styles[0]}>{row[0]}</span> ÷ <span style={styles[1]}>{row[2]}</span> = {row[1]} R <span style={styles[2]}>{row[3]}</span>
|
||||
</p>
|
||||
}
|
||||
|
||||
return <div className="solution text-center" data-bs-theme="light">
|
||||
{rows.map(displayRow)}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
export function GCF() {
|
||||
// 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 _chooseMultiplesOf = (f : number) : [number, number] => {
|
||||
const max = Math.floor(200 / f)
|
||||
return [ f * getRandomInt(max), f * getRandomInt(max) ]
|
||||
}
|
||||
|
||||
const chooseMultiplesOf = (f : number) : () => [ number, number ] => {
|
||||
return () => _chooseMultiplesOf(f)
|
||||
}
|
||||
|
||||
const chooseMultiples = () : [number, number] => {
|
||||
const f = getRandomInt(50)
|
||||
return _chooseMultiplesOf(f)
|
||||
}
|
||||
|
||||
const chooseFactors = () : [number, number] => {
|
||||
const probabilities : Array<[number, () => [number, number]]>= [
|
||||
[ 0.2, chooseFactorsRandom ],
|
||||
[ 0.2, chooseMultiples ],
|
||||
[ 0.2, chooseMultiplesOf(3) ],
|
||||
[ 0.2, chooseMultiplesOf(7) ],
|
||||
[ 0.1, chooseMultiplesOf(11) ],
|
||||
[ 0.1, chooseMultiplesOf(17) ],
|
||||
]
|
||||
const r = Math.random()
|
||||
var i = 0, accum = 0
|
||||
for (i = 0; i < probabilities.length; i++) {
|
||||
console.log([r, i, accum, probabilities[i]])
|
||||
if ((r > accum) && (r <= accum + probabilities[i][0])) break
|
||||
accum += probabilities[i][0]
|
||||
}
|
||||
if (i >= probabilities.length) i = probabilities.length - 1
|
||||
return probabilities[i][1]()
|
||||
}
|
||||
|
||||
const getSolution = (a : number, b : number) : SolutionKey => {
|
||||
var result : SolutionKey = [ ]
|
||||
if (b > a) {
|
||||
var t = b
|
||||
b = a
|
||||
a = t
|
||||
}
|
||||
while (b != 0) {
|
||||
result.push([ a, Math.floor(a / b), b, a % b ])
|
||||
var t = a % b
|
||||
a = b
|
||||
b = t
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const doCheck = (e : Event) : void => {
|
||||
e.preventDefault()
|
||||
const rightAnswer = gcf(factors[0], factors[1])
|
||||
const yourAnswer = (document.getElementById("inlineFormInputResponse") as HTMLInputElement).value
|
||||
if (rightAnswer == Number(yourAnswer)) {
|
||||
setCorrect(true)
|
||||
setFeedback(true)
|
||||
} else {
|
||||
setFeedback(true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const doNext = (e : Event) : void => {
|
||||
e.preventDefault()
|
||||
setFeedback(false)
|
||||
setCorrect(false)
|
||||
setFactors(chooseFactors())
|
||||
setSolution(null)
|
||||
document.forms[0].reset()
|
||||
}
|
||||
|
||||
const doSolution = (e : Event) : void => {
|
||||
e.preventDefault()
|
||||
if (solution === null) {
|
||||
var answerBox = document.getElementById("inlineFormInputResponse") as HTMLInputElement
|
||||
answerBox.value = String(gcf(factors[0], factors[1]))
|
||||
setSolution(<Solution rows={getSolution(factors[0], factors[1])} />)
|
||||
setCorrect(true)
|
||||
//setFeedback(true)
|
||||
} else {
|
||||
setSolution(null)
|
||||
}
|
||||
}
|
||||
|
||||
const [factors, setFactors] = useState(chooseFactors())
|
||||
|
||||
const [correct, setCorrect] = useState(false)
|
||||
const [feedback, setFeedback] = useState(false)
|
||||
const [solution, setSolution] = useState<JSX.Element|null>(null)
|
||||
|
||||
return (
|
||||
<div className="px-4 py-5 my-5 text-center">
|
||||
<h1 className="my-5">Greatest Common Factor Practice</h1>
|
||||
<p className="fs-3">What is the greatest common factor of <mark>{factors[0]}</mark> and <mark>{factors[1]}</mark>?</p>
|
||||
<form className="row row-cols-lg-auto g-3 align-items-center justify-content-center">
|
||||
<div className="col-12">
|
||||
<label className="visually-hidden" for="inlineFormInputResponse">Response</label>
|
||||
<div className="input-group">
|
||||
<input type="text" size={3} autocomplete="off" className="form-control text-center" id="inlineFormInputResponse" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<button type="submit" onClick={correct ? doNext : doCheck} className="btn btn-primary">{correct ? "Next" : "Check"}</button>
|
||||
<button type="submit" onClick={doSolution} className="ms-2 btn btn-secondary">{solution !== null ? "Hide" : "Solve"}</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className={feedback ? "visible" : "invisible"}>
|
||||
<div className={correct ? "alert alert-success m-4" : "alert alert-danger m-4"}>{correct ? "Correct" : "Try again!"}</div>
|
||||
</div>
|
||||
{solution !== null ? solution : <></>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -24,7 +24,7 @@ a:hover {
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
/*display: flex;*/
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
|
||||
131
src/lcm.tsx
Normal file
131
src/lcm.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
import { useState } from 'preact/hooks'
|
||||
import { gcf } from './lib'
|
||||
import type { JSX } from 'preact'
|
||||
|
||||
type SolutionParams = {
|
||||
factors : [ number, number ],
|
||||
gcf : number,
|
||||
result : number
|
||||
}
|
||||
|
||||
function Solution({factors, gcf, result}:SolutionParams) {
|
||||
const multipliers = [
|
||||
Math.floor(result/factors[0]),
|
||||
Math.floor(result/factors[1]),
|
||||
]
|
||||
return <div className="solution text-center" data-bs-theme="light">
|
||||
<p>GCF({factors[0]}, {factors[1]}) = {gcf}</p>
|
||||
<p>{factors[0]} × {factors[1]} ÷ {gcf} = {result}</p>
|
||||
<p>{factors[0]} × {multipliers[0]} = {result}</p>
|
||||
<p>{factors[1]} × {multipliers[1]} = {result}</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
export function LCM() {
|
||||
// choose number between 2 and max inclusive
|
||||
const getRandomInt = (max : number) : number => Math.floor(Math.random() * (max - 1) + 2)
|
||||
|
||||
const chooseFactorsRandom = () : [number, number] => {
|
||||
const f = getRandomInt(15)
|
||||
const max = Math.floor(200 / f)
|
||||
return [ f, getRandomInt(max) ]
|
||||
}
|
||||
|
||||
const _chooseMultiplesOf = (f : number) : [number, number] => {
|
||||
const max = Math.floor(200 / f)
|
||||
return [ f * getRandomInt(max), f * getRandomInt(max) ]
|
||||
}
|
||||
|
||||
/*
|
||||
const chooseMultiplesOf = (f : number) : () => [ number, number ] => {
|
||||
return () => _chooseMultiplesOf(f)
|
||||
}
|
||||
*/
|
||||
|
||||
const chooseMultiples = () : [number, number] => {
|
||||
const f = getRandomInt(20)
|
||||
return _chooseMultiplesOf(f)
|
||||
}
|
||||
|
||||
const chooseFactors = () : [number, number] => {
|
||||
const probabilities : Array<[number, () => [number, number]]>= [
|
||||
[ 0.5, chooseFactorsRandom ],
|
||||
[ 0.5, chooseMultiples ],
|
||||
]
|
||||
const r = Math.random()
|
||||
var i = 0, accum = 0
|
||||
for (i = 0; i < probabilities.length; i++) {
|
||||
//console.log([r, i, accum, probabilities[i]])
|
||||
if ((r > accum) && (r <= accum + probabilities[i][0])) break
|
||||
accum += probabilities[i][0]
|
||||
}
|
||||
if (i >= probabilities.length) i = probabilities.length - 1
|
||||
return probabilities[i][1]()
|
||||
}
|
||||
|
||||
const doCheck = (e : Event) : void => {
|
||||
e.preventDefault()
|
||||
const rightAnswer = Math.floor(factors[0] / gcf(factors[0], factors[1])) * factors[1]
|
||||
const yourAnswer = (document.getElementById("inlineFormInputResponse") as HTMLInputElement).value
|
||||
if (rightAnswer == Number(yourAnswer)) {
|
||||
setCorrect(true)
|
||||
setFeedback(true)
|
||||
} else {
|
||||
setFeedback(true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const doNext = (e : Event) : void => {
|
||||
e.preventDefault()
|
||||
setFeedback(false)
|
||||
setCorrect(false)
|
||||
setFactors(chooseFactors())
|
||||
setSolution(null)
|
||||
document.forms[0].reset()
|
||||
}
|
||||
|
||||
const doSolution = (e : Event) : void => {
|
||||
e.preventDefault()
|
||||
if (solution === null) {
|
||||
var answerBox = document.getElementById("inlineFormInputResponse") as HTMLInputElement
|
||||
const theGCF = gcf(factors[0], factors[1])
|
||||
const rightAnswer = Math.floor(factors[0] / theGCF) * factors[1]
|
||||
answerBox.value = String(rightAnswer)
|
||||
setSolution(<Solution factors={factors} gcf={theGCF} result={rightAnswer} />)
|
||||
setCorrect(true)
|
||||
//setFeedback(true)
|
||||
} else {
|
||||
setSolution(null)
|
||||
}
|
||||
}
|
||||
const [factors, setFactors] = useState(chooseFactors())
|
||||
|
||||
const [correct, setCorrect] = useState(false)
|
||||
const [feedback, setFeedback] = useState(false)
|
||||
const [solution, setSolution] = useState<JSX.Element|null>(null)
|
||||
|
||||
return (
|
||||
<div className="px-4 py-5 my-5 text-center">
|
||||
<h1 className="my-5">Least Common Multiple Practice</h1>
|
||||
<p className="fs-3">What is the least common multiple of <mark>{factors[0]}</mark> and <mark>{factors[1]}</mark>?</p>
|
||||
<form className="row row-cols-lg-auto g-3 align-items-center justify-content-center">
|
||||
<div className="col-12">
|
||||
<label className="visually-hidden" for="inlineFormInputResponse">Response</label>
|
||||
<div className="input-group">
|
||||
<input type="text" size={3} autocomplete="off" className="form-control text-center" id="inlineFormInputResponse" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<button type="submit" onClick={correct ? doNext : doCheck} className="btn btn-primary">{correct ? "Next" : "Check"}</button>
|
||||
<button type="submit" onClick={doSolution} className="ms-2 btn btn-secondary">{solution !== null ? "Hide" : "Solve"}</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className={feedback ? "visible" : "invisible"}>
|
||||
<div className={correct ? "alert alert-success m-4" : "alert alert-danger m-4"}>{correct ? "Correct" : "Try again!"}</div>
|
||||
</div>
|
||||
{solution !== null ? solution : <></>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
5
src/lib.tsx
Normal file
5
src/lib.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
export function gcf(a : number, b : number) : number {
|
||||
if (b > a) return gcf(b, a)
|
||||
else if (b == 0) return a
|
||||
else return gcf(b, a % b)
|
||||
}
|
||||
24
src/navbar.tsx
Normal file
24
src/navbar.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import Container from 'react-bootstrap/Container';
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import Nav from 'react-bootstrap/Nav';
|
||||
//import NavItem from 'react-bootstrap/NavItem'
|
||||
import RBNavbar from 'react-bootstrap/Navbar';
|
||||
//import NavDropdown from 'react-bootstrap/NavDropdown';
|
||||
|
||||
function Navbar() {
|
||||
return (
|
||||
<RBNavbar expand="lg" className="bg-body-tertiary" sticky="top">
|
||||
<Container>
|
||||
<RBNavbar.Toggle aria-controls="basic-navbar-nav" />
|
||||
<RBNavbar.Collapse id="basic-navbar-nav">
|
||||
<Nav className="me-auto">
|
||||
<NavLink to="/gcf" title="Greatest Common Factor" className={({ isActive, isPending }) => "nav-link " + (isPending ? "" : isActive ? "active" : "")}>GCF</NavLink>
|
||||
<NavLink to="/lcm" title="Least Common Multiple" className={({ isActive, isPending }) => "nav-link " + (isPending ? "" : isActive ? "active" : "")}>LCM</NavLink>
|
||||
</Nav>
|
||||
</RBNavbar.Collapse>
|
||||
</Container>
|
||||
</RBNavbar>
|
||||
);
|
||||
}
|
||||
|
||||
export default Navbar;
|
||||
@@ -1,29 +0,0 @@
|
||||
import './solution.css'
|
||||
|
||||
type SolutionRow = [Number, Number, Number, Number]
|
||||
export type SolutionKey = Array<SolutionRow>
|
||||
type SolutionParams = {
|
||||
rows : SolutionKey
|
||||
}
|
||||
|
||||
export function Solution({rows}:SolutionParams) {
|
||||
const colors = [
|
||||
"red",
|
||||
"blue",
|
||||
"green",
|
||||
"brown",
|
||||
"purple",
|
||||
"orange"
|
||||
]
|
||||
const displayRow = (row : SolutionRow, index : number) => {
|
||||
let range : number[] = [0, 1, 2]
|
||||
const styles = range.map((i)=>{return `padding:3px;color:white;background:${colors[(i+index)%colors.length]}`})
|
||||
return <p>
|
||||
<span style={styles[0]}>{row[0]}</span> ÷ <span style={styles[1]}>{row[2]}</span> = {row[1]} R <span style={styles[2]}>{row[3]}</span>
|
||||
</p>
|
||||
}
|
||||
|
||||
return <div className="solution text-center" data-bs-theme="light">
|
||||
{rows.map(displayRow)}
|
||||
</div>
|
||||
}
|
||||
Reference in New Issue
Block a user