Skip to content

Commit a4d9840

Browse files
committed
修复类型问题:解决不同算法返回类型不一致导致的TypeScript错误
1 parent 6a3bff3 commit a4d9840

File tree

4 files changed

+421
-136
lines changed

4 files changed

+421
-136
lines changed

src/App.css

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ body, html {
8686
background-color: #f8f9fa;
8787
border-radius: 4px;
8888
margin-bottom: 5px;
89+
position: relative;
90+
z-index: 10;
8991
}
9092

9193
.app-header h1 {
@@ -119,6 +121,8 @@ body, html {
119121
padding: 5px;
120122
overflow-y: auto;
121123
border-right: 1px solid var(--border-color);
124+
position: relative;
125+
z-index: 5;
122126
}
123127

124128
.left-panel h2 {
@@ -137,8 +141,10 @@ body, html {
137141
flex: 1;
138142
display: flex;
139143
flex-direction: column;
140-
padding: 5px;
144+
padding: 10px 10px 10px 20px;
141145
overflow: hidden;
146+
position: relative;
147+
z-index: 1;
142148
}
143149

144150
.center-panel svg {

src/App.tsx

Lines changed: 158 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
import { useReducer, useState } from 'react'
1+
import { useReducer, useState, useCallback, useEffect } from 'react'
22
import './App.css'
33
import CanvasComponent from './components/CanvasComponent'
44
import ControlPanel from './components/ControlPanel'
55
import CodePanel from './components/CodePanel'
66
import { useAnimation } from './hooks/useAnimation'
7-
import { animationReducer, AnimationState } from './state/animationSlice'
7+
import { animationReducer, AnimationState, INITIALIZE, AnimationTimeline } from './state/animationSlice'
88
import GitHubCorner from './components/GitHubCorner'
99
import BackToHot100 from './components/BackToHot100'
10+
import MatrixFastPower from './components/MatrixFastPower'
11+
import FormulaVisualizer from './components/FormulaVisualizer'
12+
import SimpleDPVisualizer from './components/dp/SimpleDPVisualizer'
1013

1114
// 初始状态
1215
const initialState: AnimationState = {
@@ -18,7 +21,10 @@ const initialState: AnimationState = {
1821
matrix: [],
1922
formula: '',
2023
timeline: [],
21-
playbackSpeed: 1.0
24+
playbackSpeed: 1.0,
25+
stepStatuses: [],
26+
values: [],
27+
animationInProgress: false
2228
};
2329

2430
function App() {
@@ -28,6 +34,9 @@ function App() {
2834
// 楼梯阶数配置
2935
const [stairsCount, setStairsCount] = useState(6);
3036

37+
// 当前算法的时间线
38+
const [currentTimeline, setCurrentTimeline] = useState<AnimationTimeline | null>(null);
39+
3140
// 使用动画钩子
3241
const { restartAnimation } = useAnimation(state, dispatch, stairsCount);
3342

@@ -41,13 +50,140 @@ function App() {
4150
}
4251
};
4352

53+
// 处理生成解决方案
54+
const handleGenerateSolution = useCallback((solution: {
55+
result: number;
56+
timeline: AnimationTimeline[];
57+
stepsData?: {
58+
stepStatuses: ('uncalculated' | 'calculating' | 'calculated')[];
59+
values: number[];
60+
};
61+
}) => {
62+
console.log("App 收到生成的解决方案:", {
63+
hasResult: !!solution.result,
64+
timelineLength: solution.timeline?.length || 0,
65+
stepsDataValues: solution.stepsData?.values?.length || 0,
66+
stepsDataStatuses: solution.stepsData?.stepStatuses?.length || 0
67+
});
68+
69+
// 验证接收到的数据
70+
if (!solution.timeline || solution.timeline.length === 0) {
71+
console.error("警告: 接收到的解决方案没有时间线数据!");
72+
return;
73+
}
74+
75+
// 构建有效的payload,包含合理的默认值
76+
const payload = {
77+
totalSteps: solution.timeline.length,
78+
values: solution.stepsData?.values || [],
79+
stepStatuses: solution.stepsData?.stepStatuses || [],
80+
timeline: solution.timeline
81+
};
82+
83+
console.log("初始化动画状态,payload信息:", {
84+
totalSteps: payload.totalSteps,
85+
valuesLength: payload.values.length,
86+
statusesLength: payload.stepStatuses.length,
87+
timelineLength: payload.timeline.length
88+
});
89+
90+
dispatch({ type: INITIALIZE, payload });
91+
}, [dispatch]);
92+
93+
// 选择算法类型
94+
const handleSelectAlgorithm = (algorithm: 'dp' | 'matrix' | 'formula') => {
95+
dispatch({ type: 'animation/setCurrentAlgorithm', payload: algorithm });
96+
dispatch({ type: 'animation/resetAnimation' });
97+
setTimeout(restartAnimation, 0);
98+
};
99+
100+
// 更新当前时间线
101+
useEffect(() => {
102+
if (state.timeline && state.timeline.length > 0 && state.currentStep < state.timeline.length) {
103+
setCurrentTimeline(state.timeline[state.currentStep]);
104+
} else {
105+
setCurrentTimeline(null);
106+
}
107+
}, [state.timeline, state.currentStep]);
108+
109+
const renderVisualization = () => {
110+
switch (state.currentAlgorithm) {
111+
case 'dp':
112+
return (
113+
<SimpleDPVisualizer
114+
n={stairsCount}
115+
state={state}
116+
onGenerateSolution={handleGenerateSolution}
117+
dispatch={dispatch}
118+
/>
119+
);
120+
case 'matrix':
121+
return (
122+
<MatrixFastPower
123+
n={stairsCount}
124+
state={state}
125+
currentTimeline={currentTimeline}
126+
/>
127+
);
128+
case 'formula':
129+
return (
130+
<FormulaVisualizer
131+
n={stairsCount}
132+
state={state}
133+
currentTimeline={currentTimeline}
134+
/>
135+
);
136+
default:
137+
// 对于其他算法,暂时保留原始的可视化方式
138+
return (
139+
<>
140+
<CanvasComponent
141+
state={state}
142+
width={window.innerWidth * 0.65}
143+
height={window.innerHeight * 0.7}
144+
/>
145+
<ControlPanel state={state} dispatch={dispatch} />
146+
</>
147+
);
148+
}
149+
};
150+
151+
// 渲染算法选择器
152+
const renderAlgorithmSelector = () => {
153+
const algorithms = [
154+
{ id: 'dp', name: '动态规划', color: '#4CAF50' },
155+
{ id: 'matrix', name: '矩阵快速幂', color: '#7E57C2' },
156+
{ id: 'formula', name: '通项公式', color: '#FFC107' }
157+
];
158+
159+
return (
160+
<div className="algorithm-selector">
161+
{algorithms.map(algo => (
162+
<button
163+
key={algo.id}
164+
className={`algorithm-button ${state.currentAlgorithm === algo.id ? 'active' : ''}`}
165+
style={{
166+
borderColor: algo.color,
167+
backgroundColor: state.currentAlgorithm === algo.id ? algo.color : 'transparent',
168+
color: state.currentAlgorithm === algo.id ? 'white' : algo.color
169+
}}
170+
onClick={() => handleSelectAlgorithm(algo.id as 'dp' | 'matrix' | 'formula')}
171+
>
172+
{algo.name}
173+
</button>
174+
))}
175+
</div>
176+
);
177+
};
178+
44179
return (
45180
<div className="app-container">
46181
<BackToHot100 />
47182
<GitHubCorner />
48183
<header className="app-header">
49184
<h1>爬楼梯问题算法可视化</h1>
50185
<div className="stairs-config">
186+
{renderAlgorithmSelector()}
51187
<label>
52188
楼梯阶数:
53189
<input
@@ -115,12 +251,25 @@ function App() {
115251
</div>
116252

117253
<div className="center-panel">
118-
<CanvasComponent
119-
state={state}
120-
width={window.innerWidth * 0.65}
121-
height={window.innerHeight * 0.7}
122-
/>
123-
<ControlPanel state={state} dispatch={dispatch} />
254+
{/* 标题 */}
255+
<h2 style={{
256+
textAlign: 'center',
257+
color: state.currentAlgorithm === 'dp' ? '#2196F3' :
258+
state.currentAlgorithm === 'matrix' ? '#7E57C2' :
259+
'#FF6F00',
260+
margin: '0 0 20px 0',
261+
padding: '10px',
262+
backgroundColor: 'white',
263+
borderRadius: '8px',
264+
boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
265+
}}>
266+
{state.currentAlgorithm === 'dp' ? '动态规划解法' :
267+
state.currentAlgorithm === 'matrix' ? '矩阵快速幂解法' :
268+
'通项公式解法'} - 爬楼梯问题
269+
</h2>
270+
271+
{/* 渲染具体算法可视化 */}
272+
{renderVisualization()}
124273
</div>
125274
</main>
126275
</div>

src/hooks/useAnimation.ts

Lines changed: 75 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -29,58 +29,87 @@ export function useAnimation(
2929
lastTimeStampRef.current = 0;
3030
stepStartTimeRef.current = 0;
3131

32-
let solution;
33-
34-
// 根据当前选择的算法生成解决方案
35-
switch (state.currentAlgorithm) {
36-
case 'dp':
37-
solution = generateDPSolution(n);
38-
break;
39-
case 'matrix':
40-
solution = generateMatrixSolution(n);
41-
break;
42-
case 'formula':
43-
solution = generateFormulaSolution(n);
44-
break;
45-
default:
46-
solution = generateDPSolution(n);
47-
}
32+
try {
33+
console.log("useAnimation - 开始生成解决方案,算法:", state.currentAlgorithm, "n:", n);
34+
35+
let solution;
36+
let values: number[] = [];
37+
let stepStatuses: ('uncalculated' | 'calculating' | 'calculated')[] = [];
38+
39+
// 根据当前选择的算法生成解决方案
40+
switch (state.currentAlgorithm) {
41+
case 'dp':
42+
solution = generateDPSolution(n);
43+
// DP算法返回包含stepsData的对象
44+
values = solution.stepsData?.values || [];
45+
stepStatuses = solution.stepsData?.stepStatuses || [];
46+
break;
47+
case 'matrix':
48+
solution = generateMatrixSolution(n);
49+
// 矩阵和公式算法不返回stepsData,创建空的默认值
50+
values = Array(n + 1).fill(0);
51+
stepStatuses = Array(n + 1).fill('uncalculated');
52+
break;
53+
case 'formula':
54+
solution = generateFormulaSolution(n);
55+
// 矩阵和公式算法不返回stepsData,创建空的默认值
56+
values = Array(n + 1).fill(0);
57+
stepStatuses = Array(n + 1).fill('uncalculated');
58+
break;
59+
default:
60+
solution = generateDPSolution(n);
61+
values = solution.stepsData?.values || [];
62+
stepStatuses = solution.stepsData?.stepStatuses || [];
63+
}
64+
65+
// 验证解决方案数据
66+
if (!solution || !solution.timeline || solution.timeline.length === 0) {
67+
console.error("useAnimation - 生成的解决方案无效:", solution);
68+
return;
69+
}
4870

49-
const { timeline } = solution;
50-
console.log(`生成时间线,长度: ${timeline.length}`); // 添加日志
71+
const { timeline } = solution;
72+
console.log(`useAnimation - 生成时间线成功,长度: ${timeline.length}`);
5173

52-
// 准备数据结构
53-
const nodes = [];
54-
const links = [];
74+
// 准备数据结构
75+
const nodes = [];
76+
const links = [];
5577

56-
// 初始化楼梯节点(当使用DP或矩阵时)
57-
if (state.currentAlgorithm !== 'formula') {
58-
for (let i = 0; i <= n; i++) {
59-
nodes.push({
60-
id: i,
61-
x: 50 + i * 80,
62-
y: 300 - Math.min(i * 40, 200),
63-
value: i <= 1 ? 1 : 0
64-
});
65-
66-
// 添加连接(从每个节点到前两个节点)
67-
if (i >= 2) {
68-
links.push({ source: i - 1, target: i });
69-
links.push({ source: i - 2, target: i });
78+
// 初始化楼梯节点(当使用DP或矩阵时)
79+
if (state.currentAlgorithm !== 'formula') {
80+
for (let i = 0; i <= n; i++) {
81+
nodes.push({
82+
id: i,
83+
x: 50 + i * 80,
84+
y: 300 - Math.min(i * 40, 200),
85+
value: i <= 1 ? 1 : 0
86+
});
87+
88+
// 添加连接(从每个节点到前两个节点)
89+
if (i >= 2) {
90+
links.push({ source: i - 1, target: i });
91+
links.push({ source: i - 2, target: i });
92+
}
7093
}
7194
}
72-
}
7395

74-
// 使用单一action更新所有状态
75-
dispatch({
76-
type: 'animation/initialize',
77-
payload: {
78-
timeline: timeline,
79-
staircase: { nodes, links },
80-
matrix: state.currentAlgorithm === 'matrix' ? [[1, 1], [1, 0]] : [],
81-
formula: ''
82-
}
83-
});
96+
// 使用单一action更新所有状态
97+
dispatch({
98+
type: 'animation/initialize',
99+
payload: {
100+
totalSteps: timeline.length,
101+
timeline: timeline,
102+
values: values,
103+
stepStatuses: stepStatuses,
104+
staircase: { nodes, links },
105+
matrix: state.currentAlgorithm === 'matrix' ? [[1, 1], [1, 0]] : [],
106+
formula: ''
107+
}
108+
});
109+
110+
} catch (error) {
111+
console.error("useAnimation - 生成解决方案时出错:", error);
112+
}
84113

85114
}, [state.currentAlgorithm, n, dispatch]);
86115

0 commit comments

Comments
 (0)