diff --git a/__pycache__/algebraic_steps.cpython-313.pyc b/__pycache__/algebraic_steps.cpython-313.pyc index 36092b7..b02f8cd 100644 Binary files a/__pycache__/algebraic_steps.cpython-313.pyc and b/__pycache__/algebraic_steps.cpython-313.pyc differ diff --git a/__pycache__/main.cpython-313.pyc b/__pycache__/main.cpython-313.pyc index 6cf9dc6..db1cba6 100644 Binary files a/__pycache__/main.cpython-313.pyc and b/__pycache__/main.cpython-313.pyc differ diff --git a/__pycache__/problem_generator.cpython-313.pyc b/__pycache__/problem_generator.cpython-313.pyc index fa8eaf0..3af879c 100644 Binary files a/__pycache__/problem_generator.cpython-313.pyc and b/__pycache__/problem_generator.cpython-313.pyc differ diff --git a/algebraic_steps.py b/algebraic_steps.py index 4ebb369..82d0c5e 100644 --- a/algebraic_steps.py +++ b/algebraic_steps.py @@ -95,19 +95,27 @@ def multiply_both_sides(equation, value): left_expr = parse_expr(left, transformations=transformations, evaluate=False) right_expr = parse_expr(right, transformations=transformations, evaluate=False) - if left_expr != 1 and left_expr != -1: + if left_expr != 1 and left_expr != -1 and value != 1 and value != -1: new_left_expr = cancel(left_expr * value) elif left_expr == 1: new_left_expr = value - else: + elif value == 1: + new_left_expr = left_expr + elif left_expr == -1: new_left_expr = -value + else: + new_left_expr = -left_expr - if right_expr != 1 and right_expr != -1: - new_right_expr = Mul(right_expr, value, evaluate=False) + if right_expr != 1 and right_expr != -1 and value != 1 and value != -1: + new_right_expr = safe_format(Mul(right_expr, value, evaluate=False)) elif right_expr == 1: new_right_expr = value - else: + elif value == 1: + new_right_expr = right_expr + elif right_expr == -1: new_right_expr = -value + else: + new_right_expr = -right_expr step["after"] = f"{sstr(new_left_expr)} = {sstr(new_right_expr)}" step["step"] = f"Multiply both sides by {sstr(value)}" diff --git a/main.py b/main.py index 3773f47..1193273 100644 --- a/main.py +++ b/main.py @@ -66,6 +66,17 @@ def generate_problem_message(): return problem +def main(): + problem_solved = False + while not problem_solved: + problem = generate_problem() + problem["steps"] = generate_steps(problem); + problem_solved = check_solution(problem["steps"][-1]["after"], problem["solution"]) + if not problem_solved: + print(f"issue with problem: {problem}") + + return pretty_print_steps(problem["steps"]) + def check_solution(got, solution): values = set([sympify(r.split("=")[1].strip()) for r in got.split(",")]) if is_iterable(solution) and not isinstance(solution, str): @@ -97,4 +108,8 @@ def is_iterable(obj): iter(obj) return True except TypeError: - return False \ No newline at end of file + return False + +#Starts the program +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/start.bat b/start.bat new file mode 100644 index 0000000..0494049 --- /dev/null +++ b/start.bat @@ -0,0 +1 @@ +uvicorn main:app --reload --host 0.0.0.0 --port 8000 \ No newline at end of file diff --git a/www/favicon.png b/www/favicon.png new file mode 100644 index 0000000..9b5c211 Binary files /dev/null and b/www/favicon.png differ diff --git a/www/index.html b/www/index.html index 187503f..4ff39fb 100644 --- a/www/index.html +++ b/www/index.html @@ -1,14 +1,17 @@ - + + -
Loading...
-
+ +
+
+
diff --git a/www/scripts/problem.js b/www/scripts/problem.js index 3b2d947..bbd77b7 100644 --- a/www/scripts/problem.js +++ b/www/scripts/problem.js @@ -1,15 +1,55 @@ -let state = "problem"; // problem | steps | done function showProblem() { const problemEl = document.getElementById("problem"); - const stepsEl = document.getElementById("steps"); + const stepsEl = document.getElementById("equation"); - problemEl.innerHTML = `\\(${problemData.problem}\\)`; + const formatted = formatMath(problemData.problem); + problemEl.innerHTML = `\\(${formatted}\\)`; stepsEl.innerHTML = ""; MathJax.typesetPromise(); } +function showStep() { + if (stepIndex >= problemData.steps.length) { + setTimeout(requestNextProblem, 3000); + return; + } + + const eqEl = document.getElementById("equation"); + const expEl = document.getElementById("explanation"); + + const step = problemData.steps[stepIndex]; + + expEl.innerHTML = step.step; + + // STEP 1: fade out + eqEl.classList.remove("fade-in"); + eqEl.classList.add("fade-out"); + + setTimeout(() => { + // STEP 2: update content + eqEl.innerHTML = `\\(${formatMath(step.after)}\\)`; + MathJax.typesetPromise(); + + // STEP 3: force reflow (CRUCIAL) + void eqEl.offsetWidth; + + // STEP 4: fade back in + eqEl.classList.remove("fade-out"); + eqEl.classList.add("fade-in"); + + stepIndex++; + + setTimeout(showStep, 2000); + }, 500); +} + +function startSteps() { + stepIndex = 0; + showStep(); +} + function startSequence() { setTimeout(() => { showNextStep(); @@ -29,17 +69,19 @@ function showNextStep() { } const s = problemData.steps[stepIndex]; + const formatted_step_before = formatMath(s.before); + const formatted_step_after = formatMath(s.after); const html = ` -
-
\\(${s.before}\\)
-
${s.step}
-
\\(${s.after}\\)
-

+
+
\\(${formatted_step_before}\\)
+
${s.step}
+
\\(${formatted_step_after}\\)
+
`; - stepsEl.innerHTML += html; + stepsEl.innerHTML = html; MathJax.typesetPromise(); @@ -48,3 +90,19 @@ function showNextStep() { setTimeout(showNextStep, 2000); // time between steps } +function formatMath(str) { + return str + .replace(/\*\*/g, "^") // Exponent Fix + .replace(/(\d+)\s*\*\s*x/g, "$1x") // 4*x -> 4x + .replace(/x\s*\*\s*(\d+)/g, "$1x") // x*4 -> 4x + .replace(/\b1x\b/g, "x") // 1x -> x + .replace(/(\d+)\s*\*\s*\(/g, "$1(") // 4*( -> 4( + .replace(/\)\s*\*\s*\(/g, ")(") // )*( -> )( + .replace(/x\s*\*\s*\(/g, "x(") // x*( -> x( + + // FRACTIONS (order matters!) + .replace(/\(([^()]+)\)\s*\/\s*\(([^()]+)\)/g, "\\frac{$1}{$2}") + .replace(/\(([^()]+)\)\s*\/\s*([a-zA-Z0-9]+)/g, "\\frac{$1}{$2}") + .replace(/([a-zA-Z0-9]+)\s*\/\s*\(([^()]+)\)/g, "\\frac{$1}{$2}") + .replace(/([a-zA-Z0-9]+)\s*\/\s*([a-zA-Z0-9]+)/g, "\\frac{$1}{$2}"); +} \ No newline at end of file diff --git a/www/scripts/web_sockets.js b/www/scripts/web_sockets.js index b0c997a..58b4f62 100644 --- a/www/scripts/web_sockets.js +++ b/www/scripts/web_sockets.js @@ -21,7 +21,7 @@ socket.onmessage = (event) => { showProblem(); // start animation sequence - startSequence(); + startSteps(); } }; diff --git a/www/style/styles.css b/www/style/styles.css index 4da1c9d..a64deee 100644 --- a/www/style/styles.css +++ b/www/style/styles.css @@ -1,4 +1,4 @@ -body { +html, body { margin: 0; height: 100vh; overflow: hidden; @@ -11,20 +11,91 @@ body { font-family: Arial; } -#waveCanvas { +#problem { position: absolute; + top: 10%; + left: 50%; + transform: translateX(-50%); + + font-size: 76px; + text-align: center; +} + +#equation { + position: absolute; + top: 30%; + left: 50%; + transform: translateX(-50%); + font-size: 32px; + + font-family: "Comic Sans MS", cursive; /* surprisingly effective */ + text-shadow: + 0 0 2px rgba(255,255,255,0.8), + 0 0 6px rgba(255,255,255,0.4); + transition: opacity 0.5s ease, transform 0.5s ease; +} + +#explanation { + position: absolute; + top: 45%; + left: 50%; + transform: translateX(-50%); + font-size: 24px; + opacity: 0.8; +} 28px; + +#steps { + position: absolute; + top: 27%; /* below the problem */ + left: 50%; + transform: translateX(-50%); + + width: 800px; + text-align: center; + font-size: 28px; +} + +#waveCanvas { + position: fixed; top: 0; left: 0; + width: 100%; + height: 100%; z-index: 0; } #particleCanvas { - position: absolute; + position: fixed; top: 0; left: 0; + width: 100%; + height: 100%; z-index: 0; } +.fade-out { + opacity: 0; + transform: translateX(-50%) scale(0.95); +} + +.fade-in { + opacity: 1; + transform: translateX(-50%) scale(1); +} + +.chalk-in { + opacity: 0; + transform: scale(1.05); + filter: blur(6px); +} + +.chalk-in-active { + opacity: 1; + transform: scale(1); + filter: blur(0px); + transition: all 0.4s ease; +} + @keyframes gradientShift { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; }