import { VariableExpression , VariableValue } from "../api-calls/endpoints/question/models/Variable" ; import { create , all } from "mathjs" ; const math = create ( all , { } ) ; export const checkDynamicQuestion = ( answerExpression , variables , userAnswer ) : { isCorrect : boolean ; actualAnswer : number | string ; } => { const answer = evaluate ( answerExpression , variables ) ; return { isCorrect : answer == userAnswer , actualAnswer : answer , } ; } ; export const evaluate = ( expression , variables ) : string | number => { const scope = { } ; for ( const i of variables ) { scope [ i . name ] = i . value ; } if ( math . evaluate ) { return math . evaluate ( expression . replace ( /\$/g , "" ) , scope ) ; } else { throw new Error ( "Math is not defined!" ) ; } } ; export const generateVariableValues = ( variables ) : VariableValue [ ] => { const valuedVariables = [ ] ; const dependencyOrder = resolveDependencyTree ( variables ) ; dependencyOrder . forEach ( ( value ) => valuedVariables . push ( { name : value . name , value : evaluate ( value . expression , valuedVariables ) || "" , } ) ) ; return valuedVariables ; } ; export function getVariableNames ( text ) { const regex = /\$([a-zA-Z_][a-zA-Z_0-9]*)/g ; const variableNames = [ ] ; let match ; while ( ( match = regex . exec ( text ) ) ) { variableNames . push ( match [ 1 ] ) ; } return variableNames ; } export const resolveDependencyTree = ( variableExpressions ) : VariableExpression [ ] => { interface VariableType extends VariableExpression { dependsOn : string [ ] ; } const variableDependencyTree = [ ] ; variableExpressions . forEach ( ( value ) => { const variableNames = getVariableNames ( value . expression ) ; if ( variableNames . includes ( value . name ) ) { throw new Error ( "Variable depends on itself!" ) ; } variableDependencyTree . push ( { name : value . name , expression : value . expression , dependsOn : variableNames , } ) ; } ) ; const resolvedDependencies = [ ] ; const resolvedDependenciesVariables = [ ] ; while ( variableDependencyTree . length !== 0 ) { const startSize = variableDependencyTree . length ; for ( let i = variableDependencyTree . length - 1 ; i >= 0 ; i -- ) { const variable = variableDependencyTree [ i ] ; const everyVariableResolved = variable . dependsOn . every ( ( name ) => resolvedDependencies . includes ( name ) ) ; if ( everyVariableResolved ) { resolvedDependencies . push ( variable . name ) ; resolvedDependenciesVariables . push ( variable ) ; variableDependencyTree . splice ( i , 1 ) ; } } if ( startSize === variableDependencyTree . length ) { throw new Error ( "Infinite dependencies between variables!" ) ; } } return resolvedDependenciesVariables ; } ; export const hasFittingVariables = ( question , answer , explanation , variableExpressions ) : boolean => { const variableTexts = question + answer + explanation ; const variableNames = new Set ( getVariableNames ( variableTexts ) ) ; if ( variableNames . size !== variableExpressions . length ) { return false ; } resolveDependencyTree ( variableExpressions ) ; return true ; } ;