155 lines
5.0 KiB
TypeScript
155 lines
5.0 KiB
TypeScript
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>
|
|
)
|
|
}
|