Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 0 additions & 42 deletions components/SortingVisualization.tsx

This file was deleted.

53 changes: 10 additions & 43 deletions components/visualizer/AlgorithmVisualizer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import ColorLegend from "./ColorLegend";
import { useAlgorithm } from "@/context/AlgorithmContext";
import { getAlgorithmByName } from "@/lib/algorithms";
import { SearchStep, SortingStep } from "@/lib/types";
import { getRandomValueFromArray } from "@/lib/utils";

export default function AlgorithmVisualizer() {
const { state, dispatch } = useAlgorithm();
const { currentStep, algorithm, data, target, visualizationData } = state;
const { currentStep, algorithm, data, visualizationData } = state;

// Generate a new random array
const handleGenerateNewArray = () => {
Expand All @@ -22,52 +21,22 @@ export default function AlgorithmVisualizer() {
payload: { min: 5, max: 95, length: 15 },
});

// Set a new random target for search algorithms
if (algorithm.includes("search")) {
const newData = data.slice();
const newTarget = getRandomValueFromArray(newData);
dispatch({ type: "SET_TARGET", payload: newTarget });
}

// Regenerate visualization with the new data/target
// Regenerate visualization with the new data
const algorithmFunction = getAlgorithmByName(algorithm);
if (algorithmFunction) {
try {
const viz = algorithm.includes("search")
? algorithmFunction(data, target)
: algorithmFunction(data);
// For search algorithms, the target will be set in the reducer
const viz = algorithmFunction(data, state.target);
dispatch({ type: "GENERATE_VISUALIZATION", payload: viz });
} catch (error) {
console.error("Error generating visualization:", error);
}
}
};

// Set a new target value for search algorithms
const handleSetTarget = () => {
// Only show for search algorithms
if (!algorithm.includes("search")) return;

const newTarget = prompt(
"Enter a target value to search for:",
target?.toString()
);
if (newTarget === null) return; // User canceled

const parsedTarget = parseInt(newTarget);
if (isNaN(parsedTarget)) {
alert("Please enter a valid number");
return;
}

dispatch({ type: "SET_TARGET", payload: parsedTarget });

// Regenerate visualization with the new target
const algorithmFunction = getAlgorithmByName(algorithm);
if (algorithmFunction) {
const viz = algorithmFunction(data, parsedTarget);
dispatch({ type: "GENERATE_VISUALIZATION", payload: viz });
}
// Check if the current algorithm is a search algorithm
const isSearchAlgorithm = () => {
return visualizationData?.category === "searching";
};

// Find the maximum value in the array for scaling
Expand All @@ -84,8 +53,7 @@ export default function AlgorithmVisualizer() {
);
}

const isSearchAlgorithm = algorithm.toLowerCase().includes("search");
console.log(algorithm, isSearchAlgorithm);
const isSearching = isSearchAlgorithm();

return (
<div className="space-y-8">
Expand All @@ -94,7 +62,7 @@ export default function AlgorithmVisualizer() {
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="lg:col-span-2 space-y-6">
<div className="card">
{isSearchAlgorithm ? (
{isSearching ? (
<SearchVisualization
step={visualizationData.steps[currentStep] as SearchStep}
maxValue={maxValue}
Expand All @@ -111,10 +79,9 @@ export default function AlgorithmVisualizer() {
currentStep={currentStep}
totalSteps={visualizationData.steps.length}
onGenerateNewArray={handleGenerateNewArray}
onSetTarget={isSearchAlgorithm ? handleSetTarget : undefined}
/>

<ColorLegend isSearchAlgorithm={isSearchAlgorithm} />
<ColorLegend isSearchAlgorithm={isSearching} />
</div>

<div className="lg:col-span-1">
Expand Down
59 changes: 55 additions & 4 deletions components/visualizer/SearchVisualization.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { SearchStep } from "@/lib/types";
import { useAlgorithm } from "@/context/AlgorithmContext";
import { getAlgorithmByName } from "@/lib/algorithms";
import { useState, useEffect } from "react";

interface SearchVisualizationProps {
step: SearchStep;
Expand All @@ -9,13 +12,61 @@ export default function SearchVisualization({
step,
}: SearchVisualizationProps) {
const { array, current, target, found, visited } = step;
const { state, dispatch } = useAlgorithm();
const [inputTarget, setInputTarget] = useState(target.toString());

// Update the input field when the target changes externally
useEffect(() => {
setInputTarget(target.toString());
}, [target]);

const handleTargetChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newValue = e.target.value;
setInputTarget(newValue);

// Only process valid numbers
const newTarget = parseInt(newValue);
if (!isNaN(newTarget) && newTarget !== target) {
updateTarget(newTarget);
}
};

const updateTarget = (newTarget: number) => {
console.log(newTarget);
// Update the target value
dispatch({ type: "SET_TARGET", payload: newTarget });

// Regenerate visualization with the new target
const algorithmFunction = getAlgorithmByName(state.algorithm);
console.log(algorithmFunction);
if (algorithmFunction) {
try {
const viz = algorithmFunction(state.data, newTarget);
console.log(viz);
dispatch({ type: "GENERATE_VISUALIZATION", payload: viz });
} catch (error) {
console.error("Error generating visualization:", error);
}
}
};

return (
<div className="flex flex-col items-center space-y-8 w-full p-6 bg-white">
<div className="flex items-center space-x-2 mb-4">
<div className="font-medium text-gray-600">Searching for value:</div>
<div className="text-lg font-bold text-purple-600">{target}</div>
<div className="font-medium ml-4 text-gray-600">
<div className="flex flex-wrap items-center gap-4 mb-4 w-full">
<div className="flex items-center gap-2">
<label htmlFor="target-input" className="font-medium text-gray-600">
Target Value:
</label>
<input
id="target-input"
type="number"
value={inputTarget}
onChange={handleTargetChange}
className="w-16 px-2 py-1 border border-gray-300 rounded text-center text-gray-600"
/>
</div>

<div className="font-medium ml-auto text-gray-600">
Status:
<span
className={`ml-2 font-bold ${
Expand Down
30 changes: 2 additions & 28 deletions components/visualizer/VisualizerControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ interface VisualizerControlsProps {
currentStep: number;
totalSteps: number;
onGenerateNewArray: () => void;
onSetTarget?: () => void;
}

export default function VisualizerControls({
currentStep,
totalSteps,
onGenerateNewArray,
onSetTarget,
}: VisualizerControlsProps) {
const { state, dispatch } = useAlgorithm();
const { isPlaying, speed } = state;
Expand Down Expand Up @@ -124,9 +122,9 @@ export default function VisualizerControls({
</svg>
</button>
</div>
<div>
<div className="flex flex-col">
<div className="flex justify-between text-sm mb-1">
<span className="font-medium">Progress</span>
<span className="text-sm font-medium text-gray-700">Progress</span>
<span className="text-gray-500">
Step {currentStep + 1} of {totalSteps}
</span>
Expand Down Expand Up @@ -210,30 +208,6 @@ export default function VisualizerControls({
</button>
</div>
</div>

{onSetTarget && (
<div className="pt-2">
<button
onClick={onSetTarget}
className="btn btn-primary bg-indigo-500 hover:bg-indigo-600 w-full flex items-center justify-center space-x-2 cursor-pointer"
>
<svg
className="w-5 h-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
<span>Set Target Value</span>
</button>
</div>
)}
</div>
);
}
Loading