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%; }