diff --git a/src/algorithms/dynamic-programming/pascalTriangle.js b/src/algorithms/dynamic-programming/pascalTriangle.js new file mode 100644 index 0000000..38aac6f --- /dev/null +++ b/src/algorithms/dynamic-programming/pascalTriangle.js @@ -0,0 +1,121 @@ +// src/algorithms/dynamic-programming/pascalTriangleAlgo.js + +// Top-Down (Recursive with Memoization) +export function pascalTriangleTopDown(n) { + const memo = Array.from({ length: n + 1 }, () => new Array(n + 1).fill(null)); + const steps = []; + + function solve(row, col) { + steps.push({ + type: "call", + row, + col, + memo: memo.map(r => [...r]), + message: `Calling pascal(${row}, ${col}).` + }); + + // Base case: edges of the triangle are always 1 + if (col === 0 || col === row) { + memo[row][col] = 1; + steps.push({ + type: "base_case", + row, + col, + value: 1, + memo: memo.map(r => [...r]), + message: `Base case: pascal(${row}, ${col}) = 1.` + }); + return 1; + } + + // Memoization hit + if (memo[row][col] !== null) { + steps.push({ + type: "memo_hit", + row, + col, + value: memo[row][col], + memo: memo.map(r => [...r]), + message: `Memoization hit: pascal(${row}, ${col}) = ${memo[row][col]}.` + }); + return memo[row][col]; + } + + // Recursive relation: pascal(r, c) = pascal(r-1, c-1) + pascal(r-1, c) + const val = solve(row - 1, col - 1) + solve(row - 1, col); + memo[row][col] = val; + + steps.push({ + type: "store", + row, + col, + value: val, + memo: memo.map(r => [...r]), + message: `Computed pascal(${row}, ${col}) = pascal(${row - 1}, ${col - 1}) + pascal(${row - 1}, ${col}) = ${val}. Stored in memo.` + }); + + return val; + } + + // Build the entire triangle + for (let i = 0; i <= n; i++) { + for (let j = 0; j <= i; j++) { + solve(i, j); + } + } + + const triangle = memo.map(row => row.filter(x => x !== null)); + + const visualSteps = steps.map(step => ({ + array: step.memo, + currentPosition: { row: step.row, col: step.col }, + message: step.message, + value: step.value + })); + + return { steps: visualSteps, result: triangle }; +} + + +// Bottom-Up (Iterative DP) +export function pascalTriangleBottomUp(n) { + const dp = Array.from({ length: n + 1 }, () => new Array(n + 1).fill(0)); + const steps = []; + + for (let i = 0; i <= n; i++) { + for (let j = 0; j <= i; j++) { + if (j === 0 || j === i) { + dp[i][j] = 1; + steps.push({ + type: "base_case", + row: i, + col: j, + value: 1, + dp: dp.map(r => [...r]), + message: `Base case: dp[${i}][${j}] = 1 (edges of triangle).` + }); + } else { + dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]; + steps.push({ + type: "compute", + row: i, + col: j, + value: dp[i][j], + dp: dp.map(r => [...r]), + message: `Computing dp[${i}][${j}] = dp[${i - 1}][${j - 1}] + dp[${i - 1}][${j}] = ${dp[i - 1][j - 1]} + ${dp[i - 1][j]} = ${dp[i][j]}.` + }); + } + } + } + + const triangle = dp.map(row => row.filter(x => x !== 0)); + + const visualSteps = steps.map(step => ({ + array: step.dp, + currentPosition: { row: step.row, col: step.col }, + message: step.message, + value: step.value + })); + + return { steps: visualSteps, result: triangle }; +} diff --git a/src/components/dynamic-programming/PascalTriangleVisualizer.jsx b/src/components/dynamic-programming/PascalTriangleVisualizer.jsx new file mode 100644 index 0000000..c98cebf --- /dev/null +++ b/src/components/dynamic-programming/PascalTriangleVisualizer.jsx @@ -0,0 +1,315 @@ +import React, { useState, useMemo, useEffect, useRef } from "react"; +import { + pascalTriangleTopDown, + pascalTriangleBottomUp, +} from "../../algorithms/dynamic-programming/pascalTriangle"; + +// Component to render Pascal’s Triangle visually +const PascalTriangleGrid = ({ array, currentPosition }) => { + return ( +
+ {array.map((row, rIdx) => ( +
+ {row.map((value, cIdx) => { + const isActive = + currentPosition && + currentPosition.row === rIdx && + currentPosition.col === cIdx; + + return ( +
+ {value === null || value === 0 ? "?" : value} +
+ ); + })} +
+ ))} +
+ ); +}; + +// Playback speeds +const SPEED_OPTIONS = { + Slow: 1500, + Medium: 600, + Fast: 200, +}; + +export default function PascalTriangleVisualizer() { + const [n, setN] = useState(5); + const [algorithm, setAlgorithm] = useState("topDown"); + const [steps, setSteps] = useState([]); + const [currentStep, setCurrentStep] = useState(0); + const [isPlaying, setIsPlaying] = useState(false); + const [speed, setSpeed] = useState(SPEED_OPTIONS.Medium); + const timerRef = useRef(null); + + // --- Core Logic --- + + const handleCompute = () => { + if (n < 0 || n > 10) { + alert("Please enter N between 0 and 10 for clear visualization."); + return; + } + + setIsPlaying(false); + + const { steps: newSteps } = + algorithm === "topDown" + ? pascalTriangleTopDown(n) + : pascalTriangleBottomUp(n); + + setSteps(newSteps); + setCurrentStep(0); + }; + + useEffect(() => { + handleCompute(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [n, algorithm]); + + // Auto-Play Logic + useEffect(() => { + if (isPlaying && currentStep < steps.length - 1) { + timerRef.current = setInterval(() => { + setCurrentStep((prev) => prev + 1); + }, speed); + } else if (currentStep === steps.length - 1) { + setIsPlaying(false); + } + return () => clearInterval(timerRef.current); + }, [isPlaying, currentStep, steps.length, speed]); + + const togglePlay = () => { + if (currentStep === steps.length - 1) { + setCurrentStep(0); + setIsPlaying(true); + } else { + setIsPlaying(!isPlaying); + } + }; + + const handleNext = () => { + setIsPlaying(false); + if (currentStep < steps.length - 1) setCurrentStep(currentStep + 1); + }; + + const handlePrev = () => { + setIsPlaying(false); + if (currentStep > 0) setCurrentStep(currentStep - 1); + }; + + const currentState = useMemo( + () => steps[currentStep] || {}, + [steps, currentStep] + ); + + const isFinalStep = steps.length > 0 && currentStep === steps.length - 1; + + return ( +
+
+

+ Pascal’s Triangle +

+ + {/* Concept Section */} +
+ + What is Pascal’s Triangle? + +
+

+ Pascal’s Triangle is a triangular array of numbers + where each entry is the sum of the two numbers + directly above it. The outer edges are always 1. +

+
    +
  • + Top-Down (Memoization): Recursive + approach that computes each cell using previously + stored results. +
  • +
  • + Bottom-Up (Tabulation): Iterative + approach that fills the triangle row by row. +
  • +
+
+
+ + {/* Controls */} +
+
+ + + setN(Math.max(0, Math.min(10, Number(e.target.value)))) + } + /> +
+ +
+ + +
+ + +
+ + {/* Visualization */} + {steps.length > 0 ? ( + <> +
+ + +
+ + +
+ +
+ + +
+
+ + {/* Step Counter */} +
+

+ Step {currentStep + 1} / {steps.length} +

+
+ +
+
+

+ Current Action +

+

+ {currentState.message || "Starting computation..."} +

+
+ + {currentState.array && ( + + )} + + {isFinalStep && ( +
+

+ Pascal’s Triangle of size {n} computed successfully. +

+
+ )} + +
+ + Click to View Raw Step Data (for debugging) + +
+                                    {JSON.stringify(currentState, null, 2)}
+                                
+
+
+ + ) : ( +
+

+ Welcome to the Pascal’s Triangle Dynamic Programming Visualizer. +

+

+ Enter the number of rows and choose an algorithm above to begin. +

+
+ )} +
+
+ ); +} diff --git a/src/pages/dynamic-programming/DyanmicProgrammingPage.jsx b/src/pages/dynamic-programming/DyanmicProgrammingPage.jsx index 4852b78..cb44ce0 100644 --- a/src/pages/dynamic-programming/DyanmicProgrammingPage.jsx +++ b/src/pages/dynamic-programming/DyanmicProgrammingPage.jsx @@ -4,6 +4,7 @@ import Levenshtein from "./Levenshtein"; import MatrixChainMultiplication from "./MatrixChainMultiplication"; import FibonacciSequence from "./FibonacciSequence"; import Knapsack from "./Knapsack"; +import PascalTriangle from "./PascalTriangle"; import LCSPage from "./LCS"; export default function DynamicProgrammingPage() { @@ -30,10 +31,16 @@ export default function DynamicProgrammingPage() { ); - case "Knapsack": + case "Knapsack": return (
- + +
+ ); + case "PascalTriangle": + return ( +
+
); case "LongestCommonSubsequence": @@ -103,6 +110,8 @@ export default function DynamicProgrammingPage() { + + {/* ✅ added */} diff --git a/src/pages/dynamic-programming/PascalTriangle.jsx b/src/pages/dynamic-programming/PascalTriangle.jsx new file mode 100644 index 0000000..553027c --- /dev/null +++ b/src/pages/dynamic-programming/PascalTriangle.jsx @@ -0,0 +1,8 @@ + +import PascalTriangleVisualizer from "@/components/dynamic-programming/PascalTriangleVisualizer"; +import React from "react"; + + +export default function PascalTriangle() { + return ; +} \ No newline at end of file